The following DESeq analysis uses lessons from https://github.com/hbctraining/DGE_workshop. Here we will be examining the differential expression of CALU-3 cell genes comparing anaerobic environment to aerobic environment.

Setup

### Bioconductor Github and CRAN libraries used
library(tidyverse)
library(RColorBrewer)
library(DESeq2)
library(pheatmap)
library(DEGreport)
library(ggpubr)
library(ggrepel)
library(wesanderson)
library(cowplot)
theme_set(theme_bw())

Load in data

subread.txt was produces by MSI using the following conditions (copied from the rna-seq report.html provided by UMGC/MSI:

“The RNA-Seq dataset was analyzed using the reference Human (Homo_sapiens) genome assembly “GRCh38” using annotation from Ensembl release 98. The Ensembl GTF annotation file was filtered to remove annotations for non-protein-coding features. Fastq files were evenly subsampled down to a maximum of 100,000 reads per sample. Quality of data in fastq files was assessed with FastQC. A Hisat2 splicesite file was generated from the GTF file. Hisat2 was used to align reads to a reference genome using the options ‘–dta-cufflinks –rna-strandness RF –known-splicesite-infile /panfs/roc/umgc/tmp/scratch/200226_A00223_0330_BH2WT2DSXY/demultiplex_20200302-13-02-18/Hunter_Project_027/rnaseq/splicesites.txt -x /panfs/roc/groups/3/umii/public/ensembl/Homo_sapiens/GRCh38/hisat2//genome’. Ribosomal content was determined by aligning the first 10,000 R1 reads to the Silva ribosomal database and reporting the percent of reads with alignment. Gene-level raw read counts were generated using featureCounts from the Subread R package using the options ‘-s 2 -B -p -Q 10’. Insert sizes were summarized with Picard."

The metadata file was made to include two columns of interest.
1) ATMOSPHERE with two levels: Anaerobic and Aerobic, and
2) TEST which contains the major experimental groups of this analysis.

## Load in data
data <- read.table("../data/subread.txt", header=T, row.names=1) 
meta <- read.table("../data/metadata.txt", header=T, row.names=1)
# Check that the row names of the metadata equal the column names of the **raw counts** data
all(colnames(data) == rownames(meta))
[1] TRUE

Create deseq obect

We are using a simple design ~ TEST here.

# Create DESeq2Dataset object
dds <- DESeqDataSetFromMatrix(countData = data, colData = meta, design = ~ TEST)
some variables in design formula are characters, converting to factors

The reference sample group is automatically set by alphabetical order. Set the reference to be aerobic.

dds$TEST <- relevel(dds$TEST, ref = "aerobic")

Exploratory Analysis

Heatmap

Create a heatmap of the count data to visually explore the relationships between the samples.

# Transform counts for data visualization
rld <- rlog(dds, blind=TRUE)

# Extract the rlog matrix from the object
rld_mat <- assay(rld)

# Compute pairwise correlation values
rld_cor <- cor(rld_mat)

# Plot heatmap
pheatmap(rld_cor)

Principal Component Analysis (PCA)

# Input is a matrix of log transformed values
pca <- prcomp(t(rld_mat))

# Create data frame with metadata and PC3 and PC4 values for input to ggplot
df <- cbind(meta, pca$x)
# PC1 and PC2
PC1PC2 <- ggplot(df) + geom_point(aes(x=PC1, y=PC2, color = TEST), size = 3) + 
  scale_color_manual(limits = c("aerobic", "anaerobic", "anaerobic_CRS"), 
                     values = wes_palette(n=3, name="Darjeeling1"))
# PC2 and PC3
PC2PC3 <- ggplot(df) + geom_point(aes(x=PC2, y=PC3, color = TEST), size = 3) + 
  scale_color_manual(limits = c("aerobic", "anaerobic", "anaerobic_CRS"), 
                     values = wes_palette(n=3, name="Darjeeling1"))
# Get legend
PC.Legend <- get_legend(PC2PC3)
# Plot together
plot_grid(PC1PC2 + theme(legend.position = "none"), 
          PC2PC3 + theme(legend.position = "none"), 
          PC.Legend,
          nrow = 1,
          rel_widths = c(1,1,1)
)

It appears the biggest source of variance on the first axis is whether cells were incubated aerobically or anaerobically. I want to look at the third PCA axis to see if variation between anaerobic and anaerobic_CRS samples is captured there.

In the second and third principal component, we can observe the separation of the anaerobic and anaerobic_crs samples. Imagine PC1 is going into the page and that aerobic samples are still differentiated from these two groups.

Differential Expression Analysis

Run DESeq2

# Run DESeq2 differentiol expression analysis
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
#  **Optional step** - Output normalized counts to save as a file to access outside RStudio
normalized_counts <- counts(dds, normalized=TRUE)

Fit curve to gene-wise dispersion estimates

The next step in the workflow is to fit a curve to the dispersion estimates for each gene. The idea behind fitting a curve to the data is that different genes will have different scales of biological variability, but, over all genes, there will be a distribution of reasonable estimates of dispersion.

# Plot dispersion estimates
plotDispEsts(dds)

Based on this shrinkage curve it looks like our data is a good fit for the model.

Let’s look at the different comparisons that are available to us based on our model:

resultsNames(dds)
[1] "Intercept"                     "TEST_anaerobic_vs_aerobic"     "TEST_anaerobic_CRS_vs_aerobic"

Output the results for two comparisons: aerobic vs anaerobic and anaerobic_CRS vs anaerobic.
Add gene annotation to the results dataframes ## Results ### Annotation Source

Loading required package: BiocFileCache
Loading required package: dbplyr

Attaching package: ‘dbplyr’

The following objects are masked from ‘package:dplyr’:

    ident, sql


Attaching package: ‘AnnotationHub’

The following object is masked from ‘package:Biobase’:

    cache
## Explore the grch38 table loaded by the annotables library
grch38_df <- data.frame(grch38)

Use the results function to test DEGs for the anaerobic vs. aerobic comparison.

# Output results of Wald test for contrast
contrastATM <- c("TEST", "anaerobic", "aerobic")
resATM <- results(dds, contrast = contrastATM)
resATM <- lfcShrink(dds, contrast = contrastATM, res=resATM, type = "ashr")
using 'ashr' for LFC shrinkage. If used in published research, please cite:
    Stephens, M. (2016) False discovery rates: a new deal. Biostatistics, 18:2.
    https://doi.org/10.1093/biostatistics/kxw041
summary(resATM)

out of 16239 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 583, 3.6%
LFC < 0 (down)     : 386, 2.4%
outliers [1]       : 1, 0.0062%
low counts [2]     : 9973, 61%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Convert results objects into dataframes for plotting and export

# Turn the results object into a data frame
resATM_df <- data.frame(resATM) %>%
  rownames_to_column("ensgene") %>%
  left_join(grch38_df, by = "ensgene") # Join annotation data to dataframe
# Save as csv 
write_csv(resATM_df, "../results/DEresults_anaerobicVSaerobic.csv")
# Set filtering parametes for alpha and lfc
padj.cutoff <- 0.05
lfc.cutoff <- 1
# Subset the significant results
sig_resATM_p05 <- dplyr::filter(resATM_df, padj < 0.05 & abs(log2FoldChange) > lfc.cutoff)
sig_resATM_p01 <- dplyr::filter(resATM_df, padj < 0.01 & abs(log2FoldChange) > lfc.cutoff)

#sig_resCRS <- left_join(x = sig_resCRS, y = grch38_df, by = "ensgene")
write_csv(sig_resATM_p05, "../results/DEresults_sig_anaVSaer_p05.csv")
write_csv(sig_resATM_p01, "../results/DEresults_sig_anaVSaer_p01.csv")

MA Plot

Function: Custom MA Plots

Plot log2FC on the y axis and log2 mean normalized counts on the x-axis.
Color is based on the adjusted p-value

makeMA_05 <- function(x){
  p <- ggmaplot(x, 
                #fc of 2 corresponds to the log2fc of 1 we tested in our hyp. in the results command
                fdr = 0.05, 
                fc = 2, 
                size = 1, 
                palette = alpha(c("limegreen", "firebrick2", "gray50"),0.35),
                genenames = as.vector(x$symbol),
                legend = "top", 
                top = 20,
                select.top.method   = "fc",
                font.label = c(10, "bold", "black"),
                font.legend = "bold",
                font.main = "bold",
                ggtheme = ggplot2::theme_minimal())
  p
}

makeMA_01 <- function(x){
  p <- ggmaplot(x, 
                #fc of 2 corresponds to the log2fc of 1 we tested in our hyp. in the results command
                fdr = 0.01, 
                fc = 2, 
                size = 1, 
                palette = alpha(c("limegreen", "firebrick2", "gray50"),0.35),
                genenames = as.vector(x$symbol),
                legend = "top", 
                top = 20,
                select.top.method   = "fc",
                font.label = c(10, "bold", "black"),
                font.legend = "bold",
                font.main = "bold",
                ggtheme = ggplot2::theme_minimal())
  p
}
makeMA_001 <- function(x){
  p <- ggmaplot(x, 
                #fc of 2 corresponds to the log2fc of 1 we tested in our hyp. in the results command
                fdr = 0.001, 
                fc = 2, 
                size = 1, 
                palette = alpha(c("limegreen", "firebrick2", "gray50"),0.35),
                genenames = as.vector(x$symbol),
                legend = "top", 
                top = 20,
                select.top.method   = "fc",
                font.label = c(10, "bold", "black"),
                font.legend = "bold",
                font.main = "bold",
                ggtheme = ggplot2::theme_minimal())
  p
}

Plots for anaerobic vs aerobic

maPlotATM_05 <- makeMA_05(resATM_df) + ggtitle("Anaerobic vs Aerobic (ref)") +theme(
    legend.text = element_text(size=rel(0.9)),  
    legend.title = element_blank(),
    legend.position = "top") +
  guides(colour = guide_legend(override.aes = list(alpha=0.5, size=3))) +
  scale_colour_manual(values = alpha(c("limegreen", "firebrick2", "gray60"),0.5), labels = c("Upregulated (262)", "Downregulated (104)", "NS"))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
maPlotATM_05
ggsave(plot = maPlotATM_05, filename = "../figures/anaVSaer/maPlotATM_aerREF_05.pdf", device = "pdf", height = 5, width = 6)


maPlotATM_01 <- makeMA_01(resATM_df) + ggtitle("Anaerobic vs Aerobic (ref)") +theme(
    legend.text = element_text(size=rel(0.9)),  
    legend.title = element_blank(),
    legend.position = "top") +
  guides(colour = guide_legend(override.aes = list(alpha=0.5, size=3))) +
  scale_colour_manual(values = alpha(c("limegreen", "firebrick2", "gray60"),0.5), labels = c("Upregulated (204)", "Downregulated (72)", "NS"))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
maPlotATM_01
ggsave(plot = maPlotATM_01, filename = "../figures/anaVSaer/maPlotATM_aerREF_01.pdf", device = "pdf", height = 4, width = 6)


maPlotATM_001 <- makeMA_001(resATM_df) + ggtitle("Anaerobic vs Aerobic (ref)") +theme(
    legend.text = element_text(size=rel(0.9)),  
    legend.title = element_blank(),
    legend.position = "top") +
  guides(colour = guide_legend(override.aes = list(alpha=0.5, size=3))) +
  scale_colour_manual(values = alpha(c("limegreen", "firebrick2", "gray60"),0.5), labels = c("Upregulated (117)", "Downregulated (31)", "NS"))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
maPlotATM_001
ggsave(plot = maPlotATM_001, filename = "../figures/anaVSaer/maPlotATM_aerREF_001.pdf", device = "pdf", height = 4, width = 6)

#Gene Count Plots Let’s create tibble objects from the meta and normalized_counts data frames before we start plotting. This will enable us to use the tidyverse functionality more easily.

# Create tibbles including row names
DE_meta <- meta %>% 
  rownames_to_column(var="SAMPLE_NAME") %>% 
  as_tibble()
        
normalized_counts <- normalized_counts %>% 
  data.frame() %>%
  rownames_to_column(var="gene") %>% 
  as_tibble()

Remove CRS samples from normalized counts and Meta data

norm_counts_atm <- select(normalized_counts, -starts_with("Sample.Anaerobic.CRS"))
DE_meta_atm <- DE_meta %>% filter(TEST == "anaerobic" | TEST == "aerobic")

Next I want to merge my resATM_df with normalized so that the symbol is also listed with normalized counts

normalized_resATM <- inner_join(norm_counts_atm, resATM_df, by = c("gene" = "ensgene"))
view(normalized_resATM)

The inner_join() will merge 2 data frames with respect to the “ensgene” and “gene” column, i.e. a column with the same column name in both data frames.

Often it is helpful to check the expression of multiple genes of interest at the same time. This often first requires some data wrangling.

We are going to plot the normalized count values for gene groups of interest

#making ploting function (box plot)
GroupGeneCountsBox <- function(x){
  ggplot(x, aes(x = symbol, y = normalized_counts, color = TEST)) + 
  geom_boxplot() +
  geom_point(position=position_dodge(w = 0.75)) +
  scale_color_manual(limits = c("aerobic", "anaerobic"), 
                     values = c("#003F5C","#BC5090")) +
  scale_y_log10() +
        xlab("Genes") +
        ylab("log10 Normalized Counts") +
        ggtitle("") +
        theme_bw() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    theme(plot.title = element_text(hjust = 0.5))}

Plot the normalized count values for Cytokine Genes

To do this, we first need to list the gene names of interest, then extract normalized count values for those genes.

#list genes of interest
cytogenes <- c("ENSG00000125538",
"ENSG00000115008",
"ENSG00000136689",
"ENSG00000136244",
"ENSG00000110944",
"ENSG00000169429",
"ENSG00000169245",
"ENSG00000156234",
"ENSG00000189377",
"ENSG00000198223",
"ENSG00000232810",
"ENSG00000163235",
"ENSG00000105329",
"ENSG00000109320",
"ENSG00000090339",
"ENSG00000171855"
)
#normailized counts for those cytokine genes
cyto_atm_norm <- normalized_resATM %>%
  filter (gene %in% cytogenes)

Now that we have the normalized counts for each of the genes for all samples, to plot using ggplot(), we need to gather the counts for all samples into a single column to allow us to give ggplot the one column with the values we want it to plot.

The gather() function in the tidyr package will perform this operation and will output the normalized counts for all genes for the first sample listed in the first 11 rows, followed by the normalized counts for second sample in the next 11 rows, so on and so forth.

# Gathering the columns to have normalized counts to a single column
gathered_cyto_atm <- cyto_atm_norm %>%
  gather(colnames(cyto_atm_norm)[2:12], key = "SAMPLE_NAME", value = "normalized_counts")

## check the column header in the "gathered" data frame
head(gathered_cyto_atm)

Now, if we want our counts colored by sample group, then we need to combine the metadata information with the melted normalized counts data into the same data frame for input to ggplot():

gathered_cyto_atm <- inner_join(DE_meta, gathered_cyto_atm, by = c("SAMPLE_NAME" = "SAMPLE_NAME"))

The inner_join() will merge 2 data frames with respect to the “SAMPLE_NAME” column, i.e. a column with the same column name in both data frames.

Now that we have a data frame in a format that can be utilised by ggplot easily, let’s plot!

## plot using GroupGeneCount function
cyto_plot <- GroupGeneCountsBox(gathered_cyto_atm) + ggtitle("Cyotkine Genes")
cyto_plot

Plot the normalized count values for Mucin Genes

To do this, we first need to list the gene names of interest, then extract normalized count values for those genes.

#list genes of interest
mucingenes <- c("ENSG00000185499",
"ENSG00000145113",
"ENSG00000169894",
"ENSG00000173702",
"ENSG00000184956",
"ENSG00000215182",
"ENSG00000117983"
)
#normailized counts for those mucin genes
mucin_atm_norm <- normalized_resATM %>%
  filter (gene %in% mucingenes)

Now that we have the normalized counts for each of the genes for all samples, to plot using ggplot(), we need to gather the counts for all samples into a single column to allow us to give ggplot the one column with the values we want it to plot.

The gather() function in the tidyr package will perform this operation and will output the normalized counts for all genes for the first sample listed in the first 11 rows, followed by the normalized counts for second sample in the next 11 rows, so on and so forth.

# Gathering the columns to have normalized counts to a single column
gathered_mucin_atm <- mucin_atm_norm %>%
  gather(colnames(mucin_atm_norm)[2:12], key = "SAMPLE_NAME", value = "normalized_counts")

## check the column header in the "gathered" data frame
head(gathered_mucin_atm)

Now, if we want our counts colored by sample group, then we need to combine the metadata information with the melted normalized counts data into the same data frame for input to ggplot():

gathered_mucin_atm <- inner_join(DE_meta, gathered_mucin_atm, by = c("SAMPLE_NAME" = "SAMPLE_NAME"))

The inner_join() will merge 2 data frames with respect to the “SAMPLE_NAME” column, i.e. a column with the same column name in both data frames.

Now that we have a data frame in a format that can be utilised by ggplot easily, let’s plot!

## plot using GroupGeneCount function
mucin_plot <- GroupGeneCountsBox(gathered_mucin_atm) + ggtitle("Mucin Genes")
mucin_plot

Plot the normalized count values for HIF1A

To do this, we first need to list the gene names of interest, then extract normalized count values for those genes.

#list genes of interest
HIF1A <- "ENSG00000100644"
#normailized counts for those mucin genes
hif1a_atm_norm <- normalized_resATM %>%
  filter (gene %in% HIF1A)

Now that we have the normalized counts for each of the genes for all samples, to plot using ggplot(), we need to gather the counts for all samples into a single column to allow us to give ggplot the one column with the values we want it to plot.

The gather() function in the tidyr package will perform this operation and will output the normalized counts for all genes for the first sample listed in the first 11 rows, followed by the normalized counts for second sample in the next 11 rows, so on and so forth.

# Gathering the columns to have normalized counts to a single column
gathered_hif1a_atm <- hif1a_atm_norm %>%
  gather(colnames(hif1a_atm_norm)[2:12], key = "SAMPLE_NAME", value = "normalized_counts")

## check the column header in the "gathered" data frame
head(gathered_hif1a_atm)

Now, if we want our counts colored by sample group, then we need to combine the metadata information with the melted normalized counts data into the same data frame for input to ggplot():

gathered_hif1a_atm <- inner_join(DE_meta, gathered_hif1a_atm, by = c("SAMPLE_NAME" = "SAMPLE_NAME"))

The inner_join() will merge 2 data frames with respect to the “SAMPLE_NAME” column, i.e. a column with the same column name in both data frames.

Now that we have a data frame in a format that can be utilised by ggplot easily, let’s plot!

## plot using GroupGeneCount function
HIF1A_plot <- GroupGeneCountsBox(gathered_hif1a_atm) + ggtitle("HIF1A")
HIF1A_plot

ggsave(cyto_plot, filename = "../figures/anaVSaer/cytokine_norm.pdf", device = "pdf", height = 4, width = 6)
ggsave(mucin_plot, filename = "../figures/anaVSaer/mucin_norm.pdf", device = "pdf", height = 4, width = 6)
ggsave(HIF1A_plot, filename = "../figures/anaVSaer/HIF1A_norm.pdf", device = "pdf", height = 4, width =6)

#Volcano Plots

library(EnhancedVolcano)
volcano_atm_01 <- EnhancedVolcano(resATM_df,
                lab = resATM_df$symbol,
                x = 'log2FoldChange',
                y= 'pvalue',
                xlim = c(-5,5),
                title = "Anaerobic vs Aerobic",
                subtitle = "",
                caption = "",
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 4/5,
                FCcutoff = 1,
                pCutoff = 0.01,
                pointSize = 1.5,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                col = c("grey30", "#EEC537", "#8AC1BE", "#D7462E"),
                legendPosition = 'none'
            )
volcano_atm_01

volcano_atm_05 <- EnhancedVolcano(resATM_df,
                lab = resATM_df$symbol,
                x = 'log2FoldChange',
                y= 'pvalue',
                xlim = c(-5,5),
                title = "Anaerobic vs Aerobic",
                subtitle = "",
                caption = "",
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 4/5,
                FCcutoff = 1,
                pCutoff = 0.05,
                pointSize = 1.5,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                col = c("grey30", "#EEC537", "#8AC1BE", "#D7462E"),
                legendPosition = 'none'
            )
volcano_atm_05

volcano_atm_001 <- EnhancedVolcano(resATM_df,
                lab = resATM_df$symbol,
                x = 'log2FoldChange',
                y= 'pvalue',
                xlim = c(-5,5),
                title = "Anaerobic vs Aerobic",
                subtitle = "",
                caption = "",
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 4/5,
                FCcutoff = 1,
                pCutoff = 0.001,
                pointSize = 1.5,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                col = c("grey30", "#EEC537", "#8AC1BE", "#D7462E"),
                legendPosition = 'none'
            )
volcano_atm_001

ggsave(volcano_atm_01, filename = "../figures/anaVSaer/volcano_atm_01.pdf", device = "pdf", height = 6, width = 6)
ggsave(volcano_atm_05, filename = "../figures/anaVSaer/volcano_atm_05.pdf", device = "pdf", height = 6, width = 6)
ggsave(volcano_atm_001, filename = "../figures/anaVSaer/volcano_atm_001.pdf", device = "pdf", height = 6, width = 6)

Now we want to color the dots in the volcano plot by certain gene groups, first we specify the gene groups

# Define gene groups
tightjunction <- c("TJP2", "TJP1", "TJP3", "TJAP1", "CDH1", "OCLN", "CGNL1", "CGN", "SYMPK", "CTNNB1", "SAFB")
oxstress <- c("GPX1", "GPX8", "SCD","OSGIN1", "OSER1", "OXSR1", "HIF1AN", "HIF1A", "HIF3A", "CTSB", "PRDX3", "NCF2", "NQO1", "NOXO1", "PARK7", "HMOX1", "HMOX2", "NFE2L2")
erstress <- c("ERN1", "EDEM2", "EDEM1", "EDEM3", "CALM1", "ATF6B", "ATF6", "ERN1", "EIF2AK3", "SREBF1", "CANX", "TRIB3", "DDIT3", "SERP1", "STIP1")
celldeath <- c("LDHA", "DAPK2", "DAPK3", "BAD", "PDCD6IP", "PDCD2", "PDCD11", "PDCD7", "PDCD2L", "PDCD6", "PDCD4", "FAS", "TRADD", "DAP", "DAD1", "DAP3", "CIDEB", "CIDEC", "CDIP1", "PIDD1", "DEDD2")
cytokine <- c( "IL6R", "TNFRSF11B", "TRAF6", "TNFRSF10A", "IL1R1", "IL17RB", "IL17RA", "IL18R1", "MAPK15", "MAP3K10", "MAP2K2", "MAP3K3", "MAPK7", "TNFAIP6", "TNFAIP3", "TNFAIP8", "TNFAIP1", "NFKBIA", "TLR1", "TLR9", "TLR4", "TLR5", "TLR2", "TLR3", "IL10RB", "IL10RA")
mucin <- c("MUC1", "MUC4", "MUC3A", "MUC13", "MUC6", "MUC5AC", "MUC5B")

genegroups <- do.call(c, list(tightjunction, oxstress, erstress, celldeath, cytokine))
# Load in res_dfATM 
res_dfATMvolcanogenes <- resATM_df

# Remove rows with l2fc or padj of "NA"
res_dfATMvolcanogenes <- res_dfATMvolcanogenes[!is.na(res_dfATMvolcanogenes$log2FoldChange), ]
res_dfATMvolcanogenes <- res_dfATMvolcanogenes[!is.na(res_dfATMvolcanogenes$padj), ]

# Populate a new column with a "1" if gene symbol corresponds to one of the genegroups and a "0" if not. Sort in descending order. When creating the plot, this will allow the genegroup points to be brought to the front and easily seen.
res_dfATMvolcanogenes %>% mutate(volcanointeger = ifelse(symbol %in% genegroups, 1, 0)) -> res_dfATMvolcanogenes
res_dfATMvolcanogenes <- res_dfATMvolcanogenes[order(res_dfATMvolcanogenes$volcanointeger),]

# Populate a new column with the gene symbol if l2fc is <-1 or >1 AND padj is <10e-10 (SPRR3 also included because it's visually significant). This makes labeling easier in the volcano plot. 
res_dfATMvolcanogenes %>% mutate(siggenes = ifelse(((log2FoldChange > 1 | log2FoldChange < -1) & padj < 10e-10) | symbol == "SPRR3" , symbol, "")) -> res_dfATMvolcanogenes
  # create custom key-value pairs for different cell-types
  # this can be achieved with nested ifelse statements
keyvals.colorATM <- 
  ifelse(res_dfATMvolcanogenes$symbol %in% tightjunction, "magenta", 
         ifelse(res_dfATMvolcanogenes$symbol %in% oxstress, "cyan2", 
                ifelse(res_dfATMvolcanogenes$symbol %in% erstress, "blue", 
                       ifelse(res_dfATMvolcanogenes$symbol %in% celldeath, "gold", 
                              ifelse(res_dfATMvolcanogenes$symbol %in% cytokine, "red", 
                                            "grey70")))))#)

  keyvals.colorATM[is.na(keyvals.colorATM)] <- "grey69"
  names(keyvals.colorATM)[keyvals.colorATM == "grey70"] <- 'Z rest'
  names(keyvals.colorATM)[keyvals.colorATM == "magenta"] <- 'Tight Junctions'
  names(keyvals.colorATM)[keyvals.colorATM == "cyan2"] <- 'Oxidative Stress'
  names(keyvals.colorATM)[keyvals.colorATM == "blue"] <- 'ER Stress'
  names(keyvals.colorATM)[keyvals.colorATM == "gold"] <- 'Cell Death'
  names(keyvals.colorATM)[keyvals.colorATM == "red"] <- 'Cytokines'
volcano_ATM_group_05 <- EnhancedVolcano(res_dfATMvolcanogenes,
                lab = res_dfATMvolcanogenes$siggenes,
                labSize = 3.5,
                boxedLabels = FALSE,
                drawConnectors = TRUE,
                widthConnectors = 0.05,
                colConnectors = "grey30",
                typeConnectors = "closed",
                endsConnectors = "first",
                lengthConnectors = unit(10e-5, 'npc'),
                x = 'log2FoldChange',
                y = 'padj',
                xlim = c(-4,4),
                title = NULL,
                subtitle = "",
                caption = "",
                colCustom = keyvals.colorATM,
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 0.5,
                pointSize = 3,
                FCcutoff = 1,
                pCutoff = 0.05,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                legendPosition = "none"
                )
volcano_ATM_group_05

volcano_ATM_group_01 <- EnhancedVolcano(res_dfATMvolcanogenes,
                lab = res_dfATMvolcanogenes$siggenes,
                labSize = 3.5,
                boxedLabels = FALSE,
                drawConnectors = TRUE,
                widthConnectors = 0.05,
                colConnectors = "grey30",
                typeConnectors = "closed",
                endsConnectors = "first",
                lengthConnectors = unit(10e-5, 'npc'),
                x = 'log2FoldChange',
                y = 'padj',
                xlim = c(-4,4),
                title = NULL,
                subtitle = "",
                caption = "",
                colCustom = keyvals.colorATM,
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 0.5,
                pointSize = 3,
                FCcutoff = 1,
                pCutoff = 0.01,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                legendPosition = "none"
                )
volcano_ATM_group_01

volcano_ATM_group_001 <- EnhancedVolcano(res_dfATMvolcanogenes,
                lab = res_dfATMvolcanogenes$siggenes,
                labSize = 3.5,
                boxedLabels = FALSE,
                drawConnectors = TRUE,
                widthConnectors = 0.05,
                colConnectors = "grey30",
                typeConnectors = "closed",
                endsConnectors = "first",
                lengthConnectors = unit(10e-5, 'npc'),
                x = 'log2FoldChange',
                y = 'padj',
                xlim = c(-4,4),
                title = NULL,
                subtitle = "",
                caption = "",
                colCustom = keyvals.colorATM,
                hlineCol = 'black',
                vlineCol = 'black',
                colAlpha = 0.5,
                pointSize = 3,
                FCcutoff = 1,
                pCutoff = 0.001,
                labCol = 'black',
                cutoffLineCol = 'black',
                border = "full",
                legendPosition = "none"
                )
volcano_ATM_group_001

ggsave(volcano_ATM_group_01, filename = "../figures/anaVSaer/volcano_atm_group_01.pdf", device = "pdf", height = 6, width = 6)
ggsave(volcano_ATM_group_05, filename = "../figures/anaVSaer/volcano_atm_group_05.pdf", device = "pdf", height = 6, width = 6)
ggsave(volcano_ATM_group_001, filename = "../figures/anaVSaer/volcano_atm_group_001.pdf", device = "pdf", height = 6, width = 6)
sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.6

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] EnhancedVolcano_1.6.0       annotables_0.1.91           AnnotationHub_2.20.2        BiocFileCache_1.12.1       
 [5] dbplyr_1.4.4                cowplot_1.0.0               wesanderson_0.3.6           ggrepel_0.8.2              
 [9] ggpubr_0.4.0                DEGreport_1.24.1            pheatmap_1.0.12             DESeq2_1.28.1              
[13] SummarizedExperiment_1.18.2 DelayedArray_0.14.1         matrixStats_0.56.0          Biobase_2.48.0             
[17] GenomicRanges_1.40.0        GenomeInfoDb_1.24.2         IRanges_2.22.2              S4Vectors_0.26.1           
[21] BiocGenerics_0.34.0         RColorBrewer_1.1-2          forcats_0.5.0               stringr_1.4.0              
[25] dplyr_1.0.2                 purrr_0.3.4                 readr_1.3.1                 tidyr_1.1.2                
[29] tibble_3.0.3                ggplot2_3.3.2               tidyverse_1.3.0            

loaded via a namespace (and not attached):
  [1] readxl_1.3.1                  backports_1.1.9               circlize_0.4.10               plyr_1.8.6                   
  [5] ConsensusClusterPlus_1.52.0   splines_4.0.2                 BiocParallel_1.22.0           digest_0.6.25                
  [9] invgamma_1.1                  htmltools_0.5.0               SQUAREM_2020.5                fansi_0.4.1                  
 [13] magrittr_1.5                  memoise_1.1.0                 cluster_2.1.0                 openxlsx_4.1.5               
 [17] limma_3.44.3                  ComplexHeatmap_2.4.3          annotate_1.66.0               Nozzle.R1_1.1-1              
 [21] modelr_0.1.8                  colorspace_1.4-1              blob_1.2.1                    rvest_0.3.6                  
 [25] rappdirs_0.3.1                haven_2.3.1                   xfun_0.16                     crayon_1.3.4                 
 [29] RCurl_1.98-1.2                jsonlite_1.7.0                genefilter_1.70.0             survival_3.1-12              
 [33] glue_1.4.2                    gtable_0.3.0                  zlibbioc_1.34.0               XVector_0.28.0               
 [37] GetoptLong_1.0.4              car_3.0-9                     shape_1.4.5                   abind_1.4-5                  
 [41] scales_1.1.1                  DBI_1.1.0                     edgeR_3.30.3                  rstatix_0.6.0                
 [45] Rcpp_1.0.5                    xtable_1.8-4                  lasso2_1.2-21.1               tmvnsim_1.0-2                
 [49] clue_0.3-57                   foreign_0.8-80                bit_4.0.4                     truncnorm_1.0-8              
 [53] httr_1.4.2                    ellipsis_0.3.1                pkgconfig_2.0.3               reshape_0.8.8                
 [57] XML_3.99-0.5                  farver_2.0.3                  locfit_1.5-9.4                later_1.1.0.1                
 [61] tidyselect_1.1.0              labeling_0.3                  rlang_0.4.7                   AnnotationDbi_1.50.3         
 [65] munsell_0.5.0                 BiocVersion_3.11.1            cellranger_1.1.0              tools_4.0.2                  
 [69] cli_2.0.2                     generics_0.0.2                RSQLite_2.2.0                 broom_0.7.0                  
 [73] evaluate_0.14                 fastmap_1.0.1                 ggdendro_0.1.22               yaml_2.2.1                   
 [77] knitr_1.29                    bit64_4.0.4                   fs_1.5.0                      zip_2.1.1                    
 [81] nlme_3.1-148                  mime_0.9                      xml2_1.3.2                    compiler_4.0.2               
 [85] rstudioapi_0.11               curl_4.3                      png_0.1-7                     interactiveDisplayBase_1.26.3
 [89] ggsignif_0.6.0                reprex_0.3.0                  geneplotter_1.66.0            stringi_1.4.6                
 [93] lattice_0.20-41               Matrix_1.2-18                 psych_2.0.9                   vctrs_0.3.4                  
 [97] pillar_1.4.6                  lifecycle_0.2.0               BiocManager_1.30.10           GlobalOptions_0.1.2          
[101] irlba_2.3.3                   data.table_1.13.0             bitops_1.0-6                  httpuv_1.5.4                 
[105] R6_2.4.1                      promises_1.1.1                rio_0.5.16                    MASS_7.3-51.6                
[109] assertthat_0.2.1              rjson_0.2.20                  withr_2.2.0                   mnormt_2.0.2                 
[113] GenomeInfoDbData_1.2.3        hms_0.5.3                     grid_4.0.2                    rmarkdown_2.3                
[117] ashr_2.2-47                   carData_3.0-4                 logging_0.10-108              mixsqp_0.3-43                
[121] base64enc_0.1-3               shiny_1.5.0                   lubridate_1.7.9              
LS0tCnRpdGxlOiAiREVTZXEyIGFuYWx5c2lzIGFuYWVyb2JpYyB2cyBhZXJvYmljIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBBdXRob3I6IFRhbGlhIFdpZ2dlbiBhbmQgU2FicmluYSBBcmlmCgotLS0KClRoZSBmb2xsb3dpbmcgREVTZXEgYW5hbHlzaXMgdXNlcyBsZXNzb25zIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2hiY3RyYWluaW5nL0RHRV93b3Jrc2hvcC4gSGVyZSB3ZSB3aWxsIGJlIGV4YW1pbmluZyB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gb2YgQ0FMVS0zIGNlbGwgZ2VuZXMgY29tcGFyaW5nIGFuYWVyb2JpYyBlbnZpcm9ubWVudCB0byBhZXJvYmljIGVudmlyb25tZW50LgoKIyBTZXR1cApgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMjIyBCaW9jb25kdWN0b3IgR2l0aHViIGFuZCBDUkFOIGxpYnJhcmllcyB1c2VkCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShERVNlcTIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoREVHcmVwb3J0KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYApgYGB7cn0KdGhlbWVfc2V0KHRoZW1lX2J3KCkpCmBgYAoKIyBMb2FkIGluIGRhdGEKc3VicmVhZC50eHQgd2FzIHByb2R1Y2VzIGJ5IE1TSSB1c2luZyB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMgKGNvcGllZCBmcm9tIHRoZSBybmEtc2VxIHJlcG9ydC5odG1sIHByb3ZpZGVkIGJ5IFVNR0MvTVNJOgoKPiJUaGUgUk5BLVNlcSBkYXRhc2V0IHdhcyBhbmFseXplZCB1c2luZyB0aGUgcmVmZXJlbmNlIEh1bWFuIChIb21vX3NhcGllbnMpIGdlbm9tZSBhc3NlbWJseSDigJxHUkNoMzjigJ0gdXNpbmcgYW5ub3RhdGlvbiBmcm9tIEVuc2VtYmwgcmVsZWFzZSA5OC4gVGhlIEVuc2VtYmwgR1RGIGFubm90YXRpb24gZmlsZSB3YXMgZmlsdGVyZWQgdG8gcmVtb3ZlIGFubm90YXRpb25zIGZvciBub24tcHJvdGVpbi1jb2RpbmcgZmVhdHVyZXMuIEZhc3RxIGZpbGVzIHdlcmUgZXZlbmx5IHN1YnNhbXBsZWQgZG93biB0byBhIG1heGltdW0gb2YgMTAwLDAwMCByZWFkcyBwZXIgc2FtcGxlLiBRdWFsaXR5IG9mIGRhdGEgaW4gZmFzdHEgZmlsZXMgd2FzIGFzc2Vzc2VkIHdpdGggRmFzdFFDLiBBIEhpc2F0MiBzcGxpY2VzaXRlIGZpbGUgd2FzIGdlbmVyYXRlZCBmcm9tIHRoZSBHVEYgZmlsZS4gSGlzYXQyIHdhcyB1c2VkIHRvIGFsaWduIHJlYWRzIHRvIGEgcmVmZXJlbmNlIGdlbm9tZSB1c2luZyB0aGUgb3B0aW9ucyDigJjigJNkdGEtY3VmZmxpbmtzIOKAk3JuYS1zdHJhbmRuZXNzIFJGIOKAk2tub3duLXNwbGljZXNpdGUtaW5maWxlIC9wYW5mcy9yb2MvdW1nYy90bXAvc2NyYXRjaC8yMDAyMjZfQTAwMjIzXzAzMzBfQkgyV1QyRFNYWS9kZW11bHRpcGxleF8yMDIwMDMwMi0xMy0wMi0xOC9IdW50ZXJfUHJvamVjdF8wMjcvcm5hc2VxL3NwbGljZXNpdGVzLnR4dCAteCAvcGFuZnMvcm9jL2dyb3Vwcy8zL3VtaWkvcHVibGljL2Vuc2VtYmwvSG9tb19zYXBpZW5zL0dSQ2gzOC9oaXNhdDIvL2dlbm9tZeKAmS4gUmlib3NvbWFsIGNvbnRlbnQgd2FzIGRldGVybWluZWQgYnkgYWxpZ25pbmcgdGhlIGZpcnN0IDEwLDAwMCBSMSByZWFkcyB0byB0aGUgU2lsdmEgcmlib3NvbWFsIGRhdGFiYXNlIGFuZCByZXBvcnRpbmcgdGhlIHBlcmNlbnQgb2YgcmVhZHMgd2l0aCBhbGlnbm1lbnQuIEdlbmUtbGV2ZWwgcmF3IHJlYWQgY291bnRzIHdlcmUgZ2VuZXJhdGVkIHVzaW5nIGZlYXR1cmVDb3VudHMgZnJvbSB0aGUgU3VicmVhZCBSIHBhY2thZ2UgdXNpbmcgdGhlIG9wdGlvbnMg4oCYLXMgMiAtQiAtcCAtUSAxMOKAmS4gSW5zZXJ0IHNpemVzIHdlcmUgc3VtbWFyaXplZCB3aXRoIFBpY2FyZC4iCgpUaGUgbWV0YWRhdGEgZmlsZSB3YXMgbWFkZSB0byBpbmNsdWRlIHR3byBjb2x1bW5zIG9mIGludGVyZXN0LiAgIAoxKSBBVE1PU1BIRVJFIHdpdGggdHdvIGxldmVsczogQW5hZXJvYmljIGFuZCBBZXJvYmljLCBhbmQgICAKMikgVEVTVCB3aGljaCBjb250YWlucyB0aGUgbWFqb3IgZXhwZXJpbWVudGFsIGdyb3VwcyBvZiB0aGlzIGFuYWx5c2lzLiAgCmBgYHtyfQojIyBMb2FkIGluIGRhdGEKZGF0YSA8LSByZWFkLnRhYmxlKCIuLi9kYXRhL3N1YnJlYWQudHh0IiwgaGVhZGVyPVQsIHJvdy5uYW1lcz0xKSAKbWV0YSA8LSByZWFkLnRhYmxlKCIuLi9kYXRhL21ldGFkYXRhLnR4dCIsIGhlYWRlcj1ULCByb3cubmFtZXM9MSkKYGBgCgpgYGB7cn0KIyBDaGVjayB0aGF0IHRoZSByb3cgbmFtZXMgb2YgdGhlIG1ldGFkYXRhIGVxdWFsIHRoZSBjb2x1bW4gbmFtZXMgb2YgdGhlICoqcmF3IGNvdW50cyoqIGRhdGEKYWxsKGNvbG5hbWVzKGRhdGEpID09IHJvd25hbWVzKG1ldGEpKQpgYGAKCgojIENyZWF0ZSBkZXNlcSBvYmVjdApXZSBhcmUgdXNpbmcgYSBzaW1wbGUgZGVzaWduIH4gVEVTVCBoZXJlLgpgYGB7cn0KIyBDcmVhdGUgREVTZXEyRGF0YXNldCBvYmplY3QKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gZGF0YSwgY29sRGF0YSA9IG1ldGEsIGRlc2lnbiA9IH4gVEVTVCkKYGBgCgpUaGUgcmVmZXJlbmNlIHNhbXBsZSBncm91cCBpcyBhdXRvbWF0aWNhbGx5IHNldCBieSBhbHBoYWJldGljYWwgb3JkZXIuIFNldCB0aGUgcmVmZXJlbmNlIHRvIGJlIGFlcm9iaWMuCmBgYHtyfQpkZHMkVEVTVCA8LSByZWxldmVsKGRkcyRURVNULCByZWYgPSAiYWVyb2JpYyIpCmBgYAojIEV4cGxvcmF0b3J5IEFuYWx5c2lzCiMjIEhlYXRtYXAgCkNyZWF0ZSBhIGhlYXRtYXAgb2YgdGhlIGNvdW50IGRhdGEgdG8gdmlzdWFsbHkgZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSBzYW1wbGVzLgpgYGB7cn0KIyBUcmFuc2Zvcm0gY291bnRzIGZvciBkYXRhIHZpc3VhbGl6YXRpb24KcmxkIDwtIHJsb2coZGRzLCBibGluZD1UUlVFKQoKIyBFeHRyYWN0IHRoZSBybG9nIG1hdHJpeCBmcm9tIHRoZSBvYmplY3QKcmxkX21hdCA8LSBhc3NheShybGQpCgojIENvbXB1dGUgcGFpcndpc2UgY29ycmVsYXRpb24gdmFsdWVzCnJsZF9jb3IgPC0gY29yKHJsZF9tYXQpCgojIFBsb3QgaGVhdG1hcApwaGVhdG1hcChybGRfY29yKQpgYGAgIAoKIyMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKQpgYGB7ciBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodD00fQojIElucHV0IGlzIGEgbWF0cml4IG9mIGxvZyB0cmFuc2Zvcm1lZCB2YWx1ZXMKcGNhIDwtIHByY29tcCh0KHJsZF9tYXQpKQoKIyBDcmVhdGUgZGF0YSBmcmFtZSB3aXRoIG1ldGFkYXRhIGFuZCBQQzMgYW5kIFBDNCB2YWx1ZXMgZm9yIGlucHV0IHRvIGdncGxvdApkZiA8LSBjYmluZChtZXRhLCBwY2EkeCkKIyBQQzEgYW5kIFBDMgpQQzFQQzIgPC0gZ2dwbG90KGRmKSArIGdlb21fcG9pbnQoYWVzKHg9UEMxLCB5PVBDMiwgY29sb3IgPSBURVNUKSwgc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKGxpbWl0cyA9IGMoImFlcm9iaWMiLCAiYW5hZXJvYmljIiwgImFuYWVyb2JpY19DUlMiKSwgCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHdlc19wYWxldHRlKG49MywgbmFtZT0iRGFyamVlbGluZzEiKSkKIyBQQzIgYW5kIFBDMwpQQzJQQzMgPC0gZ2dwbG90KGRmKSArIGdlb21fcG9pbnQoYWVzKHg9UEMyLCB5PVBDMywgY29sb3IgPSBURVNUKSwgc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKGxpbWl0cyA9IGMoImFlcm9iaWMiLCAiYW5hZXJvYmljIiwgImFuYWVyb2JpY19DUlMiKSwgCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHdlc19wYWxldHRlKG49MywgbmFtZT0iRGFyamVlbGluZzEiKSkKIyBHZXQgbGVnZW5kClBDLkxlZ2VuZCA8LSBnZXRfbGVnZW5kKFBDMlBDMykKIyBQbG90IHRvZ2V0aGVyCnBsb3RfZ3JpZChQQzFQQzIgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLCAKICAgICAgICAgIFBDMlBDMyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIAogICAgICAgICAgUEMuTGVnZW5kLAogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICByZWxfd2lkdGhzID0gYygxLDEsMSkKKQpgYGAgIAoKSXQgYXBwZWFycyB0aGUgYmlnZ2VzdCBzb3VyY2Ugb2YgdmFyaWFuY2Ugb24gdGhlIGZpcnN0IGF4aXMgaXMgd2hldGhlciBjZWxscyB3ZXJlIGluY3ViYXRlZCBhZXJvYmljYWxseSBvciBhbmFlcm9iaWNhbGx5LiBJIHdhbnQgdG8gbG9vayBhdCB0aGUgdGhpcmQgUENBIGF4aXMgdG8gc2VlIGlmIHZhcmlhdGlvbiBiZXR3ZWVuIGFuYWVyb2JpYyBhbmQgYW5hZXJvYmljX0NSUyBzYW1wbGVzIGlzIGNhcHR1cmVkIHRoZXJlLiAgCgpJbiB0aGUgc2Vjb25kIGFuZCB0aGlyZCBwcmluY2lwYWwgY29tcG9uZW50LCB3ZSBjYW4gb2JzZXJ2ZSB0aGUgc2VwYXJhdGlvbiBvZiB0aGUgYW5hZXJvYmljIGFuZCBhbmFlcm9iaWNfY3JzIHNhbXBsZXMuIEltYWdpbmUgUEMxIGlzIGdvaW5nIGludG8gdGhlIHBhZ2UgYW5kIHRoYXQgYWVyb2JpYyBzYW1wbGVzIGFyZSBzdGlsbCBkaWZmZXJlbnRpYXRlZCBmcm9tIHRoZXNlIHR3byBncm91cHMuICAKCiMgRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gQW5hbHlzaXMKIyMgUnVuIERFU2VxMgpgYGB7cn0KIyBSdW4gREVTZXEyIGRpZmZlcmVudGlvbCBleHByZXNzaW9uIGFuYWx5c2lzCmRkcyA8LSBERVNlcShkZHMpCiMgICoqT3B0aW9uYWwgc3RlcCoqIC0gT3V0cHV0IG5vcm1hbGl6ZWQgY291bnRzIHRvIHNhdmUgYXMgYSBmaWxlIHRvIGFjY2VzcyBvdXRzaWRlIFJTdHVkaW8Kbm9ybWFsaXplZF9jb3VudHMgPC0gY291bnRzKGRkcywgbm9ybWFsaXplZD1UUlVFKQpgYGAKIyMgRml0IGN1cnZlIHRvIGdlbmUtd2lzZSBkaXNwZXJzaW9uIGVzdGltYXRlcwpUaGUgbmV4dCBzdGVwIGluIHRoZSB3b3JrZmxvdyBpcyB0byBmaXQgYSBjdXJ2ZSB0byB0aGUgZGlzcGVyc2lvbiBlc3RpbWF0ZXMgZm9yIGVhY2ggZ2VuZS4gVGhlIGlkZWEgYmVoaW5kIGZpdHRpbmcgYSBjdXJ2ZSB0byB0aGUgZGF0YSBpcyB0aGF0IGRpZmZlcmVudCBnZW5lcyB3aWxsIGhhdmUgZGlmZmVyZW50IHNjYWxlcyBvZiBiaW9sb2dpY2FsIHZhcmlhYmlsaXR5LCBidXQsIG92ZXIgYWxsIGdlbmVzLCB0aGVyZSB3aWxsIGJlIGEgZGlzdHJpYnV0aW9uIG9mIHJlYXNvbmFibGUgZXN0aW1hdGVzIG9mIGRpc3BlcnNpb24uCmBgYHtyfQojIFBsb3QgZGlzcGVyc2lvbiBlc3RpbWF0ZXMKcGxvdERpc3BFc3RzKGRkcykKYGBgICAKCkJhc2VkIG9uIHRoaXMgc2hyaW5rYWdlIGN1cnZlIGl0IGxvb2tzIGxpa2Ugb3VyIGRhdGEgaXMgYSBnb29kIGZpdCBmb3IgdGhlIG1vZGVsLgoKTGV0J3MgbG9vayBhdCB0aGUgZGlmZmVyZW50IGNvbXBhcmlzb25zIHRoYXQgYXJlIGF2YWlsYWJsZSB0byB1cyBiYXNlZCBvbiBvdXIgbW9kZWw6CmBgYHtyfQpyZXN1bHRzTmFtZXMoZGRzKQpgYGAKT3V0cHV0IHRoZSByZXN1bHRzIGZvciB0d28gY29tcGFyaXNvbnM6IGFlcm9iaWMgdnMgYW5hZXJvYmljIGFuZCBhbmFlcm9iaWNfQ1JTIHZzIGFuYWVyb2JpYy4gIApBZGQgZ2VuZSBhbm5vdGF0aW9uIHRvIHRoZSByZXN1bHRzIGRhdGFmcmFtZXMKIyMgUmVzdWx0cwojIyMgQW5ub3RhdGlvbiBTb3VyY2UKYGBge3IgZWNobz1GQUxTRX0KbGlicmFyeShBbm5vdGF0aW9uSHViKQpsaWJyYXJ5KGFubm90YWJsZXMpCmBgYAoKYGBge3J9CiMjIEV4cGxvcmUgdGhlIGdyY2gzOCB0YWJsZSBsb2FkZWQgYnkgdGhlIGFubm90YWJsZXMgbGlicmFyeQpncmNoMzhfZGYgPC0gZGF0YS5mcmFtZShncmNoMzgpCmBgYApVc2UgdGhlIHJlc3VsdHMgZnVuY3Rpb24gdG8gdGVzdCBERUdzIGZvciB0aGUgYW5hZXJvYmljIHZzLiBhZXJvYmljIGNvbXBhcmlzb24uCgoKYGBge3J9CiMgT3V0cHV0IHJlc3VsdHMgb2YgV2FsZCB0ZXN0IGZvciBjb250cmFzdApjb250cmFzdEFUTSA8LSBjKCJURVNUIiwgImFuYWVyb2JpYyIsICJhZXJvYmljIikKcmVzQVRNIDwtIHJlc3VsdHMoZGRzLCBjb250cmFzdCA9IGNvbnRyYXN0QVRNKQpyZXNBVE0gPC0gbGZjU2hyaW5rKGRkcywgY29udHJhc3QgPSBjb250cmFzdEFUTSwgcmVzPXJlc0FUTSwgdHlwZSA9ICJhc2hyIikKc3VtbWFyeShyZXNBVE0pCmBgYAoKQ29udmVydCByZXN1bHRzIG9iamVjdHMgaW50byBkYXRhZnJhbWVzIGZvciBwbG90dGluZyBhbmQgZXhwb3J0CmBgYHtyfQojIFR1cm4gdGhlIHJlc3VsdHMgb2JqZWN0IGludG8gYSBkYXRhIGZyYW1lCnJlc0FUTV9kZiA8LSBkYXRhLmZyYW1lKHJlc0FUTSkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNnZW5lIikgJT4lCiAgbGVmdF9qb2luKGdyY2gzOF9kZiwgYnkgPSAiZW5zZ2VuZSIpICMgSm9pbiBhbm5vdGF0aW9uIGRhdGEgdG8gZGF0YWZyYW1lCiMgU2F2ZSBhcyBjc3YgCndyaXRlX2NzdihyZXNBVE1fZGYsICIuLi9yZXN1bHRzL0RFcmVzdWx0c19hbmFlcm9iaWNWU2Flcm9iaWMuY3N2IikKYGBgCgoKYGBge3J9CiMgU2V0IGZpbHRlcmluZyBwYXJhbWV0ZXMgZm9yIGFscGhhIGFuZCBsZmMKcGFkai5jdXRvZmYgPC0gMC4wNQpsZmMuY3V0b2ZmIDwtIDEKIyBTdWJzZXQgdGhlIHNpZ25pZmljYW50IHJlc3VsdHMKc2lnX3Jlc0FUTV9wMDUgPC0gZHBseXI6OmZpbHRlcihyZXNBVE1fZGYsIHBhZGogPCAwLjA1ICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+IGxmYy5jdXRvZmYpCnNpZ19yZXNBVE1fcDAxIDwtIGRwbHlyOjpmaWx0ZXIocmVzQVRNX2RmLCBwYWRqIDwgMC4wMSAmIGFicyhsb2cyRm9sZENoYW5nZSkgPiBsZmMuY3V0b2ZmKQoKI3NpZ19yZXNDUlMgPC0gbGVmdF9qb2luKHggPSBzaWdfcmVzQ1JTLCB5ID0gZ3JjaDM4X2RmLCBieSA9ICJlbnNnZW5lIikKd3JpdGVfY3N2KHNpZ19yZXNBVE1fcDA1LCAiLi4vcmVzdWx0cy9ERXJlc3VsdHNfc2lnX2FuYVZTYWVyX3AwNS5jc3YiKQp3cml0ZV9jc3Yoc2lnX3Jlc0FUTV9wMDEsICIuLi9yZXN1bHRzL0RFcmVzdWx0c19zaWdfYW5hVlNhZXJfcDAxLmNzdiIpCmBgYAojIE1BIFBsb3QKIyMjIEZ1bmN0aW9uOiBDdXN0b20gTUEgUGxvdHMKUGxvdCBsb2cyRkMgb24gdGhlIHkgYXhpcyBhbmQgbG9nMiBtZWFuIG5vcm1hbGl6ZWQgY291bnRzIG9uIHRoZSB4LWF4aXMuICAKQ29sb3IgaXMgYmFzZWQgb24gdGhlIGFkanVzdGVkIHAtdmFsdWUKYGBge3J9Cm1ha2VNQV8wNSA8LSBmdW5jdGlvbih4KXsKICBwIDwtIGdnbWFwbG90KHgsIAogICAgICAgICAgICAgICAgI2ZjIG9mIDIgY29ycmVzcG9uZHMgdG8gdGhlIGxvZzJmYyBvZiAxIHdlIHRlc3RlZCBpbiBvdXIgaHlwLiBpbiB0aGUgcmVzdWx0cyBjb21tYW5kCiAgICAgICAgICAgICAgICBmZHIgPSAwLjA1LCAKICAgICAgICAgICAgICAgIGZjID0gMiwgCiAgICAgICAgICAgICAgICBzaXplID0gMSwgCiAgICAgICAgICAgICAgICBwYWxldHRlID0gYWxwaGEoYygibGltZWdyZWVuIiwgImZpcmVicmljazIiLCAiZ3JheTUwIiksMC4zNSksCiAgICAgICAgICAgICAgICBnZW5lbmFtZXMgPSBhcy52ZWN0b3IoeCRzeW1ib2wpLAogICAgICAgICAgICAgICAgbGVnZW5kID0gInRvcCIsIAogICAgICAgICAgICAgICAgdG9wID0gMjAsCiAgICAgICAgICAgICAgICBzZWxlY3QudG9wLm1ldGhvZAk9ICJmYyIsCiAgICAgICAgICAgICAgICBmb250LmxhYmVsID0gYygxMCwgImJvbGQiLCAiYmxhY2siKSwKICAgICAgICAgICAgICAgIGZvbnQubGVnZW5kID0gImJvbGQiLAogICAgICAgICAgICAgICAgZm9udC5tYWluID0gImJvbGQiLAogICAgICAgICAgICAgICAgZ2d0aGVtZSA9IGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSkKICBwCn0KCm1ha2VNQV8wMSA8LSBmdW5jdGlvbih4KXsKICBwIDwtIGdnbWFwbG90KHgsIAogICAgICAgICAgICAgICAgI2ZjIG9mIDIgY29ycmVzcG9uZHMgdG8gdGhlIGxvZzJmYyBvZiAxIHdlIHRlc3RlZCBpbiBvdXIgaHlwLiBpbiB0aGUgcmVzdWx0cyBjb21tYW5kCiAgICAgICAgICAgICAgICBmZHIgPSAwLjAxLCAKICAgICAgICAgICAgICAgIGZjID0gMiwgCiAgICAgICAgICAgICAgICBzaXplID0gMSwgCiAgICAgICAgICAgICAgICBwYWxldHRlID0gYWxwaGEoYygibGltZWdyZWVuIiwgImZpcmVicmljazIiLCAiZ3JheTUwIiksMC4zNSksCiAgICAgICAgICAgICAgICBnZW5lbmFtZXMgPSBhcy52ZWN0b3IoeCRzeW1ib2wpLAogICAgICAgICAgICAgICAgbGVnZW5kID0gInRvcCIsIAogICAgICAgICAgICAgICAgdG9wID0gMjAsCiAgICAgICAgICAgICAgICBzZWxlY3QudG9wLm1ldGhvZAk9ICJmYyIsCiAgICAgICAgICAgICAgICBmb250LmxhYmVsID0gYygxMCwgImJvbGQiLCAiYmxhY2siKSwKICAgICAgICAgICAgICAgIGZvbnQubGVnZW5kID0gImJvbGQiLAogICAgICAgICAgICAgICAgZm9udC5tYWluID0gImJvbGQiLAogICAgICAgICAgICAgICAgZ2d0aGVtZSA9IGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSkKICBwCn0KbWFrZU1BXzAwMSA8LSBmdW5jdGlvbih4KXsKICBwIDwtIGdnbWFwbG90KHgsIAogICAgICAgICAgICAgICAgI2ZjIG9mIDIgY29ycmVzcG9uZHMgdG8gdGhlIGxvZzJmYyBvZiAxIHdlIHRlc3RlZCBpbiBvdXIgaHlwLiBpbiB0aGUgcmVzdWx0cyBjb21tYW5kCiAgICAgICAgICAgICAgICBmZHIgPSAwLjAwMSwgCiAgICAgICAgICAgICAgICBmYyA9IDIsIAogICAgICAgICAgICAgICAgc2l6ZSA9IDEsIAogICAgICAgICAgICAgICAgcGFsZXR0ZSA9IGFscGhhKGMoImxpbWVncmVlbiIsICJmaXJlYnJpY2syIiwgImdyYXk1MCIpLDAuMzUpLAogICAgICAgICAgICAgICAgZ2VuZW5hbWVzID0gYXMudmVjdG9yKHgkc3ltYm9sKSwKICAgICAgICAgICAgICAgIGxlZ2VuZCA9ICJ0b3AiLCAKICAgICAgICAgICAgICAgIHRvcCA9IDIwLAogICAgICAgICAgICAgICAgc2VsZWN0LnRvcC5tZXRob2QJPSAiZmMiLAogICAgICAgICAgICAgICAgZm9udC5sYWJlbCA9IGMoMTAsICJib2xkIiwgImJsYWNrIiksCiAgICAgICAgICAgICAgICBmb250LmxlZ2VuZCA9ICJib2xkIiwKICAgICAgICAgICAgICAgIGZvbnQubWFpbiA9ICJib2xkIiwKICAgICAgICAgICAgICAgIGdndGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkpCiAgcAp9CmBgYCAgCgoKCiMjIFBsb3RzIGZvciBhbmFlcm9iaWMgdnMgYWVyb2JpYwpgYGB7cn0KbWFQbG90QVRNXzA1IDwtIG1ha2VNQV8wNShyZXNBVE1fZGYpICsgZ2d0aXRsZSgiQW5hZXJvYmljIHZzIEFlcm9iaWMgKHJlZikiKSArdGhlbWUoCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjkpKSwgIAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC41LCBzaXplPTMpKSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYWxwaGEoYygibGltZWdyZWVuIiwgImZpcmVicmljazIiLCAiZ3JheTYwIiksMC41KSwgbGFiZWxzID0gYygiVXByZWd1bGF0ZWQgKDI2MikiLCAiRG93bnJlZ3VsYXRlZCAoMTA0KSIsICJOUyIpKQoKbWFQbG90QVRNXzA1Cmdnc2F2ZShwbG90ID0gbWFQbG90QVRNXzA1LCBmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2FuYVZTYWVyL21hUGxvdEFUTV9hZXJSRUZfMDUucGRmIiwgZGV2aWNlID0gInBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNikKCm1hUGxvdEFUTV8wMSA8LSBtYWtlTUFfMDEocmVzQVRNX2RmKSArIGdndGl0bGUoIkFuYWVyb2JpYyB2cyBBZXJvYmljIChyZWYpIikgK3RoZW1lKAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoMC45KSksICAKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNSwgc2l6ZT0zKSkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGFscGhhKGMoImxpbWVncmVlbiIsICJmaXJlYnJpY2syIiwgImdyYXk2MCIpLDAuNSksIGxhYmVscyA9IGMoIlVwcmVndWxhdGVkICgyMDQpIiwgIkRvd25yZWd1bGF0ZWQgKDcyKSIsICJOUyIpKQptYVBsb3RBVE1fMDEKZ2dzYXZlKHBsb3QgPSBtYVBsb3RBVE1fMDEsIGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvYW5hVlNhZXIvbWFQbG90QVRNX2FlclJFRl8wMS5wZGYiLCBkZXZpY2UgPSAicGRmIiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA2KQoKbWFQbG90QVRNXzAwMSA8LSBtYWtlTUFfMDAxKHJlc0FUTV9kZikgKyBnZ3RpdGxlKCJBbmFlcm9iaWMgdnMgQWVyb2JpYyAocmVmKSIpICt0aGVtZSgKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDAuOSkpLCAgCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjUsIHNpemU9MykpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbHBoYShjKCJsaW1lZ3JlZW4iLCAiZmlyZWJyaWNrMiIsICJncmF5NjAiKSwwLjUpLCBsYWJlbHMgPSBjKCJVcHJlZ3VsYXRlZCAoMTE3KSIsICJEb3ducmVndWxhdGVkICgzMSkiLCAiTlMiKSkKbWFQbG90QVRNXzAwMQpnZ3NhdmUocGxvdCA9IG1hUGxvdEFUTV8wMDEsIGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvYW5hVlNhZXIvbWFQbG90QVRNX2FlclJFRl8wMDEucGRmIiwgZGV2aWNlID0gInBkZiIsIGhlaWdodCA9IDQsIHdpZHRoID0gNikKYGBgICAKCgojR2VuZSBDb3VudCBQbG90cwpMZXQncyBjcmVhdGUgdGliYmxlIG9iamVjdHMgZnJvbSB0aGUgbWV0YSBhbmQgbm9ybWFsaXplZF9jb3VudHMgZGF0YSBmcmFtZXMgYmVmb3JlIHdlIHN0YXJ0IHBsb3R0aW5nLiBUaGlzIHdpbGwgZW5hYmxlIHVzIHRvIHVzZSB0aGUgdGlkeXZlcnNlIGZ1bmN0aW9uYWxpdHkgbW9yZSBlYXNpbHkuCgpgYGB7cn0KIyBDcmVhdGUgdGliYmxlcyBpbmNsdWRpbmcgcm93IG5hbWVzCkRFX21ldGEgPC0gbWV0YSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhcj0iU0FNUExFX05BTUUiKSAlPiUgCiAgYXNfdGliYmxlKCkKICAgICAgICAKbm9ybWFsaXplZF9jb3VudHMgPC0gbm9ybWFsaXplZF9jb3VudHMgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUKICByb3duYW1lc190b19jb2x1bW4odmFyPSJnZW5lIikgJT4lIAogIGFzX3RpYmJsZSgpCmBgYAoKClJlbW92ZSBDUlMgc2FtcGxlcyBmcm9tIG5vcm1hbGl6ZWQgY291bnRzIGFuZCBNZXRhIGRhdGEKYGBge3J9Cm5vcm1fY291bnRzX2F0bSA8LSBzZWxlY3Qobm9ybWFsaXplZF9jb3VudHMsIC1zdGFydHNfd2l0aCgiU2FtcGxlLkFuYWVyb2JpYy5DUlMiKSkKYGBgCmBgYHtyfQpERV9tZXRhX2F0bSA8LSBERV9tZXRhICU+JSBmaWx0ZXIoVEVTVCA9PSAiYW5hZXJvYmljIiB8IFRFU1QgPT0gImFlcm9iaWMiKQpgYGAKCk5leHQgSSB3YW50IHRvIG1lcmdlIG15IHJlc0FUTV9kZiB3aXRoIG5vcm1hbGl6ZWQgc28gdGhhdCB0aGUgc3ltYm9sIGlzIGFsc28gbGlzdGVkIHdpdGggbm9ybWFsaXplZCBjb3VudHMKYGBge3J9Cm5vcm1hbGl6ZWRfcmVzQVRNIDwtIGlubmVyX2pvaW4obm9ybV9jb3VudHNfYXRtLCByZXNBVE1fZGYsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZ2VuZSIpKQp2aWV3KG5vcm1hbGl6ZWRfcmVzQVRNKQpgYGAKVGhlIGlubmVyX2pvaW4oKSB3aWxsIG1lcmdlIDIgZGF0YSBmcmFtZXMgd2l0aCByZXNwZWN0IHRvIHRoZSAiZW5zZ2VuZSIgYW5kICJnZW5lIiBjb2x1bW4sIGkuZS4gYSBjb2x1bW4gd2l0aCB0aGUgc2FtZSBjb2x1bW4gbmFtZSBpbiBib3RoIGRhdGEgZnJhbWVzLgoKT2Z0ZW4gaXQgaXMgaGVscGZ1bCB0byBjaGVjayB0aGUgZXhwcmVzc2lvbiBvZiBtdWx0aXBsZSBnZW5lcyBvZiBpbnRlcmVzdCBhdCB0aGUgc2FtZSB0aW1lLiBUaGlzIG9mdGVuIGZpcnN0IHJlcXVpcmVzIHNvbWUgZGF0YSB3cmFuZ2xpbmcuCgpXZSBhcmUgZ29pbmcgdG8gcGxvdCB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZXMgZm9yIGdlbmUgZ3JvdXBzIG9mIGludGVyZXN0CgpgYGB7cn0KI21ha2luZyBwbG90aW5nIGZ1bmN0aW9uIChib3ggcGxvdCkKR3JvdXBHZW5lQ291bnRzQm94IDwtIGZ1bmN0aW9uKHgpewogIGdncGxvdCh4LCBhZXMoeCA9IHN5bWJvbCwgeSA9IG5vcm1hbGl6ZWRfY291bnRzLCBjb2xvciA9IFRFU1QpKSArIAogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHcgPSAwLjc1KSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChsaW1pdHMgPSBjKCJhZXJvYmljIiwgImFuYWVyb2JpYyIpLCAKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiIzAwM0Y1QyIsIiNCQzUwOTAiKSkgKwogIHNjYWxlX3lfbG9nMTAoKSArCiAgICAgICAgeGxhYigiR2VuZXMiKSArCiAgICAgICAgeWxhYigibG9nMTAgTm9ybWFsaXplZCBDb3VudHMiKSArCiAgICAgICAgZ2d0aXRsZSgiIikgKwogICAgICAgIHRoZW1lX2J3KCkgKwoJdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwoJdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpfQpgYGAKCgpQbG90IHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlcyBmb3IgQ3l0b2tpbmUgR2VuZXMKClRvIGRvIHRoaXMsIHdlIGZpcnN0IG5lZWQgdG8gbGlzdCB0aGUgZ2VuZSBuYW1lcyBvZiBpbnRlcmVzdCwgdGhlbiBleHRyYWN0IG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzIGZvciB0aG9zZSBnZW5lcy4KYGBge3J9CiNsaXN0IGdlbmVzIG9mIGludGVyZXN0CmN5dG9nZW5lcyA8LSBjKCJFTlNHMDAwMDAxMjU1MzgiLAoiRU5TRzAwMDAwMTE1MDA4IiwKIkVOU0cwMDAwMDEzNjY4OSIsCiJFTlNHMDAwMDAxMzYyNDQiLAoiRU5TRzAwMDAwMTEwOTQ0IiwKIkVOU0cwMDAwMDE2OTQyOSIsCiJFTlNHMDAwMDAxNjkyNDUiLAoiRU5TRzAwMDAwMTU2MjM0IiwKIkVOU0cwMDAwMDE4OTM3NyIsCiJFTlNHMDAwMDAxOTgyMjMiLAoiRU5TRzAwMDAwMjMyODEwIiwKIkVOU0cwMDAwMDE2MzIzNSIsCiJFTlNHMDAwMDAxMDUzMjkiLAoiRU5TRzAwMDAwMTA5MzIwIiwKIkVOU0cwMDAwMDA5MDMzOSIsCiJFTlNHMDAwMDAxNzE4NTUiCikKI25vcm1haWxpemVkIGNvdW50cyBmb3IgdGhvc2UgY3l0b2tpbmUgZ2VuZXMKY3l0b19hdG1fbm9ybSA8LSBub3JtYWxpemVkX3Jlc0FUTSAlPiUKICBmaWx0ZXIgKGdlbmUgJWluJSBjeXRvZ2VuZXMpCmBgYAoKTm93IHRoYXQgd2UgaGF2ZSB0aGUgbm9ybWFsaXplZCBjb3VudHMgZm9yIGVhY2ggb2YgdGhlIGdlbmVzIGZvciBhbGwgc2FtcGxlcywgdG8gcGxvdCB1c2luZyBnZ3Bsb3QoKSwgd2UgbmVlZCB0byBnYXRoZXIgdGhlIGNvdW50cyBmb3IgYWxsIHNhbXBsZXMgaW50byBhIHNpbmdsZSBjb2x1bW4gdG8gYWxsb3cgdXMgdG8gZ2l2ZSBnZ3Bsb3QgdGhlIG9uZSBjb2x1bW4gd2l0aCB0aGUgdmFsdWVzIHdlIHdhbnQgaXQgdG8gcGxvdC4KClRoZSBnYXRoZXIoKSBmdW5jdGlvbiBpbiB0aGUgdGlkeXIgcGFja2FnZSB3aWxsIHBlcmZvcm0gdGhpcyBvcGVyYXRpb24gYW5kIHdpbGwgb3V0cHV0IHRoZSBub3JtYWxpemVkIGNvdW50cyBmb3IgYWxsIGdlbmVzIGZvciB0aGUgZmlyc3Qgc2FtcGxlIGxpc3RlZCBpbiB0aGUgZmlyc3QgMTEgcm93cywgZm9sbG93ZWQgYnkgdGhlIG5vcm1hbGl6ZWQgY291bnRzIGZvciBzZWNvbmQgc2FtcGxlIGluIHRoZSBuZXh0IDExIHJvd3MsIHNvIG9uIGFuZCBzbyBmb3J0aC4KCgpgYGB7cn0KIyBHYXRoZXJpbmcgdGhlIGNvbHVtbnMgdG8gaGF2ZSBub3JtYWxpemVkIGNvdW50cyB0byBhIHNpbmdsZSBjb2x1bW4KZ2F0aGVyZWRfY3l0b19hdG0gPC0gY3l0b19hdG1fbm9ybSAlPiUKICBnYXRoZXIoY29sbmFtZXMoY3l0b19hdG1fbm9ybSlbMjoxMl0sIGtleSA9ICJTQU1QTEVfTkFNRSIsIHZhbHVlID0gIm5vcm1hbGl6ZWRfY291bnRzIikKCiMjIGNoZWNrIHRoZSBjb2x1bW4gaGVhZGVyIGluIHRoZSAiZ2F0aGVyZWQiIGRhdGEgZnJhbWUKaGVhZChnYXRoZXJlZF9jeXRvX2F0bSkKYGBgCgpOb3csIGlmIHdlIHdhbnQgb3VyIGNvdW50cyBjb2xvcmVkIGJ5IHNhbXBsZSBncm91cCwgdGhlbiB3ZSBuZWVkIHRvIGNvbWJpbmUgdGhlIG1ldGFkYXRhIGluZm9ybWF0aW9uIHdpdGggdGhlIG1lbHRlZCBub3JtYWxpemVkIGNvdW50cyBkYXRhIGludG8gdGhlIHNhbWUgZGF0YSBmcmFtZSBmb3IgaW5wdXQgdG8gZ2dwbG90KCk6CmBgYHtyfQpnYXRoZXJlZF9jeXRvX2F0bSA8LSBpbm5lcl9qb2luKERFX21ldGEsIGdhdGhlcmVkX2N5dG9fYXRtLCBieSA9IGMoIlNBTVBMRV9OQU1FIiA9ICJTQU1QTEVfTkFNRSIpKQpgYGAKVGhlIGlubmVyX2pvaW4oKSB3aWxsIG1lcmdlIDIgZGF0YSBmcmFtZXMgd2l0aCByZXNwZWN0IHRvIHRoZSAiU0FNUExFX05BTUUiIGNvbHVtbiwgaS5lLiBhIGNvbHVtbiB3aXRoIHRoZSBzYW1lIGNvbHVtbiBuYW1lIGluIGJvdGggZGF0YSBmcmFtZXMuCgpOb3cgdGhhdCB3ZSBoYXZlIGEgZGF0YSBmcmFtZSBpbiBhIGZvcm1hdCB0aGF0IGNhbiBiZSB1dGlsaXNlZCBieSBnZ3Bsb3QgZWFzaWx5LCBsZXQncyBwbG90IQoKYGBge3J9CiMjIHBsb3QgdXNpbmcgR3JvdXBHZW5lQ291bnQgZnVuY3Rpb24KY3l0b19wbG90IDwtIEdyb3VwR2VuZUNvdW50c0JveChnYXRoZXJlZF9jeXRvX2F0bSkgKyBnZ3RpdGxlKCJDeW90a2luZSBHZW5lcyIpCmN5dG9fcGxvdApgYGAKCgpQbG90IHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlcyBmb3IgTXVjaW4gR2VuZXMKClRvIGRvIHRoaXMsIHdlIGZpcnN0IG5lZWQgdG8gbGlzdCB0aGUgZ2VuZSBuYW1lcyBvZiBpbnRlcmVzdCwgdGhlbiBleHRyYWN0IG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzIGZvciB0aG9zZSBnZW5lcy4KYGBge3J9CiNsaXN0IGdlbmVzIG9mIGludGVyZXN0Cm11Y2luZ2VuZXMgPC0gYygiRU5TRzAwMDAwMTg1NDk5IiwKIkVOU0cwMDAwMDE0NTExMyIsCiJFTlNHMDAwMDAxNjk4OTQiLAoiRU5TRzAwMDAwMTczNzAyIiwKIkVOU0cwMDAwMDE4NDk1NiIsCiJFTlNHMDAwMDAyMTUxODIiLAoiRU5TRzAwMDAwMTE3OTgzIgopCiNub3JtYWlsaXplZCBjb3VudHMgZm9yIHRob3NlIG11Y2luIGdlbmVzCm11Y2luX2F0bV9ub3JtIDwtIG5vcm1hbGl6ZWRfcmVzQVRNICU+JQogIGZpbHRlciAoZ2VuZSAlaW4lIG11Y2luZ2VuZXMpCmBgYAoKTm93IHRoYXQgd2UgaGF2ZSB0aGUgbm9ybWFsaXplZCBjb3VudHMgZm9yIGVhY2ggb2YgdGhlIGdlbmVzIGZvciBhbGwgc2FtcGxlcywgdG8gcGxvdCB1c2luZyBnZ3Bsb3QoKSwgd2UgbmVlZCB0byBnYXRoZXIgdGhlIGNvdW50cyBmb3IgYWxsIHNhbXBsZXMgaW50byBhIHNpbmdsZSBjb2x1bW4gdG8gYWxsb3cgdXMgdG8gZ2l2ZSBnZ3Bsb3QgdGhlIG9uZSBjb2x1bW4gd2l0aCB0aGUgdmFsdWVzIHdlIHdhbnQgaXQgdG8gcGxvdC4KClRoZSBnYXRoZXIoKSBmdW5jdGlvbiBpbiB0aGUgdGlkeXIgcGFja2FnZSB3aWxsIHBlcmZvcm0gdGhpcyBvcGVyYXRpb24gYW5kIHdpbGwgb3V0cHV0IHRoZSBub3JtYWxpemVkIGNvdW50cyBmb3IgYWxsIGdlbmVzIGZvciB0aGUgZmlyc3Qgc2FtcGxlIGxpc3RlZCBpbiB0aGUgZmlyc3QgMTEgcm93cywgZm9sbG93ZWQgYnkgdGhlIG5vcm1hbGl6ZWQgY291bnRzIGZvciBzZWNvbmQgc2FtcGxlIGluIHRoZSBuZXh0IDExIHJvd3MsIHNvIG9uIGFuZCBzbyBmb3J0aC4KCmBgYHtyfQojIEdhdGhlcmluZyB0aGUgY29sdW1ucyB0byBoYXZlIG5vcm1hbGl6ZWQgY291bnRzIHRvIGEgc2luZ2xlIGNvbHVtbgpnYXRoZXJlZF9tdWNpbl9hdG0gPC0gbXVjaW5fYXRtX25vcm0gJT4lCiAgZ2F0aGVyKGNvbG5hbWVzKG11Y2luX2F0bV9ub3JtKVsyOjEyXSwga2V5ID0gIlNBTVBMRV9OQU1FIiwgdmFsdWUgPSAibm9ybWFsaXplZF9jb3VudHMiKQoKIyMgY2hlY2sgdGhlIGNvbHVtbiBoZWFkZXIgaW4gdGhlICJnYXRoZXJlZCIgZGF0YSBmcmFtZQpoZWFkKGdhdGhlcmVkX211Y2luX2F0bSkKYGBgCgpOb3csIGlmIHdlIHdhbnQgb3VyIGNvdW50cyBjb2xvcmVkIGJ5IHNhbXBsZSBncm91cCwgdGhlbiB3ZSBuZWVkIHRvIGNvbWJpbmUgdGhlIG1ldGFkYXRhIGluZm9ybWF0aW9uIHdpdGggdGhlIG1lbHRlZCBub3JtYWxpemVkIGNvdW50cyBkYXRhIGludG8gdGhlIHNhbWUgZGF0YSBmcmFtZSBmb3IgaW5wdXQgdG8gZ2dwbG90KCk6CmBgYHtyfQpnYXRoZXJlZF9tdWNpbl9hdG0gPC0gaW5uZXJfam9pbihERV9tZXRhLCBnYXRoZXJlZF9tdWNpbl9hdG0sIGJ5ID0gYygiU0FNUExFX05BTUUiID0gIlNBTVBMRV9OQU1FIikpCmBgYApUaGUgaW5uZXJfam9pbigpIHdpbGwgbWVyZ2UgMiBkYXRhIGZyYW1lcyB3aXRoIHJlc3BlY3QgdG8gdGhlICJTQU1QTEVfTkFNRSIgY29sdW1uLCBpLmUuIGEgY29sdW1uIHdpdGggdGhlIHNhbWUgY29sdW1uIG5hbWUgaW4gYm90aCBkYXRhIGZyYW1lcy4KCk5vdyB0aGF0IHdlIGhhdmUgYSBkYXRhIGZyYW1lIGluIGEgZm9ybWF0IHRoYXQgY2FuIGJlIHV0aWxpc2VkIGJ5IGdncGxvdCBlYXNpbHksIGxldCdzIHBsb3QhCgpgYGB7cn0KIyMgcGxvdCB1c2luZyBHcm91cEdlbmVDb3VudCBmdW5jdGlvbgptdWNpbl9wbG90IDwtIEdyb3VwR2VuZUNvdW50c0JveChnYXRoZXJlZF9tdWNpbl9hdG0pICsgZ2d0aXRsZSgiTXVjaW4gR2VuZXMiKQptdWNpbl9wbG90CmBgYAoKClBsb3QgdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzIGZvciBISUYxQQoKVG8gZG8gdGhpcywgd2UgZmlyc3QgbmVlZCB0byBsaXN0IHRoZSBnZW5lIG5hbWVzIG9mIGludGVyZXN0LCB0aGVuIGV4dHJhY3Qgbm9ybWFsaXplZCBjb3VudCB2YWx1ZXMgZm9yIHRob3NlIGdlbmVzLgpgYGB7cn0KI2xpc3QgZ2VuZXMgb2YgaW50ZXJlc3QKSElGMUEgPC0gIkVOU0cwMDAwMDEwMDY0NCIKI25vcm1haWxpemVkIGNvdW50cyBmb3IgdGhvc2UgbXVjaW4gZ2VuZXMKaGlmMWFfYXRtX25vcm0gPC0gbm9ybWFsaXplZF9yZXNBVE0gJT4lCiAgZmlsdGVyIChnZW5lICVpbiUgSElGMUEpCmBgYAoKTm93IHRoYXQgd2UgaGF2ZSB0aGUgbm9ybWFsaXplZCBjb3VudHMgZm9yIGVhY2ggb2YgdGhlIGdlbmVzIGZvciBhbGwgc2FtcGxlcywgdG8gcGxvdCB1c2luZyBnZ3Bsb3QoKSwgd2UgbmVlZCB0byBnYXRoZXIgdGhlIGNvdW50cyBmb3IgYWxsIHNhbXBsZXMgaW50byBhIHNpbmdsZSBjb2x1bW4gdG8gYWxsb3cgdXMgdG8gZ2l2ZSBnZ3Bsb3QgdGhlIG9uZSBjb2x1bW4gd2l0aCB0aGUgdmFsdWVzIHdlIHdhbnQgaXQgdG8gcGxvdC4KClRoZSBnYXRoZXIoKSBmdW5jdGlvbiBpbiB0aGUgdGlkeXIgcGFja2FnZSB3aWxsIHBlcmZvcm0gdGhpcyBvcGVyYXRpb24gYW5kIHdpbGwgb3V0cHV0IHRoZSBub3JtYWxpemVkIGNvdW50cyBmb3IgYWxsIGdlbmVzIGZvciB0aGUgZmlyc3Qgc2FtcGxlIGxpc3RlZCBpbiB0aGUgZmlyc3QgMTEgcm93cywgZm9sbG93ZWQgYnkgdGhlIG5vcm1hbGl6ZWQgY291bnRzIGZvciBzZWNvbmQgc2FtcGxlIGluIHRoZSBuZXh0IDExIHJvd3MsIHNvIG9uIGFuZCBzbyBmb3J0aC4KCmBgYHtyfQojIEdhdGhlcmluZyB0aGUgY29sdW1ucyB0byBoYXZlIG5vcm1hbGl6ZWQgY291bnRzIHRvIGEgc2luZ2xlIGNvbHVtbgpnYXRoZXJlZF9oaWYxYV9hdG0gPC0gaGlmMWFfYXRtX25vcm0gJT4lCiAgZ2F0aGVyKGNvbG5hbWVzKGhpZjFhX2F0bV9ub3JtKVsyOjEyXSwga2V5ID0gIlNBTVBMRV9OQU1FIiwgdmFsdWUgPSAibm9ybWFsaXplZF9jb3VudHMiKQoKIyMgY2hlY2sgdGhlIGNvbHVtbiBoZWFkZXIgaW4gdGhlICJnYXRoZXJlZCIgZGF0YSBmcmFtZQpoZWFkKGdhdGhlcmVkX2hpZjFhX2F0bSkKYGBgCgpOb3csIGlmIHdlIHdhbnQgb3VyIGNvdW50cyBjb2xvcmVkIGJ5IHNhbXBsZSBncm91cCwgdGhlbiB3ZSBuZWVkIHRvIGNvbWJpbmUgdGhlIG1ldGFkYXRhIGluZm9ybWF0aW9uIHdpdGggdGhlIG1lbHRlZCBub3JtYWxpemVkIGNvdW50cyBkYXRhIGludG8gdGhlIHNhbWUgZGF0YSBmcmFtZSBmb3IgaW5wdXQgdG8gZ2dwbG90KCk6CmBgYHtyfQpnYXRoZXJlZF9oaWYxYV9hdG0gPC0gaW5uZXJfam9pbihERV9tZXRhLCBnYXRoZXJlZF9oaWYxYV9hdG0sIGJ5ID0gYygiU0FNUExFX05BTUUiID0gIlNBTVBMRV9OQU1FIikpCmBgYApUaGUgaW5uZXJfam9pbigpIHdpbGwgbWVyZ2UgMiBkYXRhIGZyYW1lcyB3aXRoIHJlc3BlY3QgdG8gdGhlICJTQU1QTEVfTkFNRSIgY29sdW1uLCBpLmUuIGEgY29sdW1uIHdpdGggdGhlIHNhbWUgY29sdW1uIG5hbWUgaW4gYm90aCBkYXRhIGZyYW1lcy4KCk5vdyB0aGF0IHdlIGhhdmUgYSBkYXRhIGZyYW1lIGluIGEgZm9ybWF0IHRoYXQgY2FuIGJlIHV0aWxpc2VkIGJ5IGdncGxvdCBlYXNpbHksIGxldCdzIHBsb3QhCgpgYGB7cn0KIyMgcGxvdCB1c2luZyBHcm91cEdlbmVDb3VudCBmdW5jdGlvbgpISUYxQV9wbG90IDwtIEdyb3VwR2VuZUNvdW50c0JveChnYXRoZXJlZF9oaWYxYV9hdG0pICsgZ2d0aXRsZSgiSElGMUEiKQpISUYxQV9wbG90CmBgYApgYGB7cn0KZ2dzYXZlKGN5dG9fcGxvdCwgZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9hbmFWU2Flci9jeXRva2luZV9ub3JtLnBkZiIsIGRldmljZSA9ICJwZGYiLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDYpCmdnc2F2ZShtdWNpbl9wbG90LCBmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2FuYVZTYWVyL211Y2luX25vcm0ucGRmIiwgZGV2aWNlID0gInBkZiIsIGhlaWdodCA9IDQsIHdpZHRoID0gNikKZ2dzYXZlKEhJRjFBX3Bsb3QsIGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvYW5hVlNhZXIvSElGMUFfbm9ybS5wZGYiLCBkZXZpY2UgPSAicGRmIiwgaGVpZ2h0ID0gNCwgd2lkdGggPTYpCmBgYAoKI1ZvbGNhbm8gUGxvdHMKYGBge3J9CmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQpgYGAKCgpgYGB7cn0Kdm9sY2Fub19hdG1fMDEgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc0FUTV9kZiwKICAgICAgICAgICAgICAgIGxhYiA9IHJlc0FUTV9kZiRzeW1ib2wsCiAgICAgICAgICAgICAgICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywKICAgICAgICAgICAgICAgIHk9ICdwdmFsdWUnLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoLTUsNSksCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJBbmFlcm9iaWMgdnMgQWVyb2JpYyIsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgY2FwdGlvbiA9ICIiLAogICAgICAgICAgICAgICAgaGxpbmVDb2wgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgdmxpbmVDb2wgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSA0LzUsCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEsCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wMSwKICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDEuNSwKICAgICAgICAgICAgICAgIGxhYkNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICBjdXRvZmZMaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGJvcmRlciA9ICJmdWxsIiwKICAgICAgICAgICAgICAgIGNvbCA9IGMoImdyZXkzMCIsICIjRUVDNTM3IiwgIiM4QUMxQkUiLCAiI0Q3NDYyRSIpLAogICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAnbm9uZScKICAgICAgICAgICAgKQp2b2xjYW5vX2F0bV8wMQpgYGAKCmBgYHtyfQp2b2xjYW5vX2F0bV8wNSA8LSBFbmhhbmNlZFZvbGNhbm8ocmVzQVRNX2RmLAogICAgICAgICAgICAgICAgbGFiID0gcmVzQVRNX2RmJHN5bWJvbCwKICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgICAgICAgICAgICAgeT0gJ3B2YWx1ZScsCiAgICAgICAgICAgICAgICB4bGltID0gYygtNSw1KSwKICAgICAgICAgICAgICAgIHRpdGxlID0gIkFuYWVyb2JpYyB2cyBBZXJvYmljIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICAgICAgICAgICBjYXB0aW9uID0gIiIsCiAgICAgICAgICAgICAgICBobGluZUNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICB2bGluZUNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICBjb2xBbHBoYSA9IDQvNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMS41LAogICAgICAgICAgICAgICAgbGFiQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGN1dG9mZkxpbmVDb2wgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgYm9yZGVyID0gImZ1bGwiLAogICAgICAgICAgICAgICAgY29sID0gYygiZ3JleTMwIiwgIiNFRUM1MzciLCAiIzhBQzFCRSIsICIjRDc0NjJFIiksCiAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdub25lJwogICAgICAgICAgICApCnZvbGNhbm9fYXRtXzA1CmBgYAoKYGBge3J9CnZvbGNhbm9fYXRtXzAwMSA8LSBFbmhhbmNlZFZvbGNhbm8ocmVzQVRNX2RmLAogICAgICAgICAgICAgICAgbGFiID0gcmVzQVRNX2RmJHN5bWJvbCwKICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgICAgICAgICAgICAgeT0gJ3B2YWx1ZScsCiAgICAgICAgICAgICAgICB4bGltID0gYygtNSw1KSwKICAgICAgICAgICAgICAgIHRpdGxlID0gIkFuYWVyb2JpYyB2cyBBZXJvYmljIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICAgICAgICAgICBjYXB0aW9uID0gIiIsCiAgICAgICAgICAgICAgICBobGluZUNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICB2bGluZUNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICBjb2xBbHBoYSA9IDQvNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjAwMSwKICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDEuNSwKICAgICAgICAgICAgICAgIGxhYkNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICBjdXRvZmZMaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGJvcmRlciA9ICJmdWxsIiwKICAgICAgICAgICAgICAgIGNvbCA9IGMoImdyZXkzMCIsICIjRUVDNTM3IiwgIiM4QUMxQkUiLCAiI0Q3NDYyRSIpLAogICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAnbm9uZScKICAgICAgICAgICAgKQp2b2xjYW5vX2F0bV8wMDEKYGBgCgpgYGB7cn0KZ2dzYXZlKHZvbGNhbm9fYXRtXzAxLCBmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2FuYVZTYWVyL3ZvbGNhbm9fYXRtXzAxLnBkZiIsIGRldmljZSA9ICJwZGYiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDYpCmdnc2F2ZSh2b2xjYW5vX2F0bV8wNSwgZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9hbmFWU2Flci92b2xjYW5vX2F0bV8wNS5wZGYiLCBkZXZpY2UgPSAicGRmIiwgaGVpZ2h0ID0gNiwgd2lkdGggPSA2KQpnZ3NhdmUodm9sY2Fub19hdG1fMDAxLCBmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2FuYVZTYWVyL3ZvbGNhbm9fYXRtXzAwMS5wZGYiLCBkZXZpY2UgPSAicGRmIiwgaGVpZ2h0ID0gNiwgd2lkdGggPSA2KQoKYGBgCgoKTm93IHdlIHdhbnQgdG8gY29sb3IgdGhlIGRvdHMgaW4gdGhlIHZvbGNhbm8gcGxvdCBieSBjZXJ0YWluIGdlbmUgZ3JvdXBzLCBmaXJzdCB3ZSBzcGVjaWZ5IHRoZSBnZW5lIGdyb3VwcwpgYGB7cn0KIyBEZWZpbmUgZ2VuZSBncm91cHMKdGlnaHRqdW5jdGlvbiA8LSBjKCJUSlAyIiwgIlRKUDEiLCAiVEpQMyIsICJUSkFQMSIsICJDREgxIiwgIk9DTE4iLCAiQ0dOTDEiLCAiQ0dOIiwgIlNZTVBLIiwgIkNUTk5CMSIsICJTQUZCIikKb3hzdHJlc3MgPC0gYygiR1BYMSIsICJHUFg4IiwgIlNDRCIsIk9TR0lOMSIsICJPU0VSMSIsICJPWFNSMSIsICJISUYxQU4iLCAiSElGMUEiLCAiSElGM0EiLCAiQ1RTQiIsICJQUkRYMyIsICJOQ0YyIiwgIk5RTzEiLCAiTk9YTzEiLCAiUEFSSzciLCAiSE1PWDEiLCAiSE1PWDIiLCAiTkZFMkwyIikKZXJzdHJlc3MgPC0gYygiRVJOMSIsICJFREVNMiIsICJFREVNMSIsICJFREVNMyIsICJDQUxNMSIsICJBVEY2QiIsICJBVEY2IiwgIkVSTjEiLCAiRUlGMkFLMyIsICJTUkVCRjEiLCAiQ0FOWCIsICJUUklCMyIsICJERElUMyIsICJTRVJQMSIsICJTVElQMSIpCmNlbGxkZWF0aCA8LSBjKCJMREhBIiwgIkRBUEsyIiwgIkRBUEszIiwgIkJBRCIsICJQRENENklQIiwgIlBEQ0QyIiwgIlBEQ0QxMSIsICJQRENENyIsICJQRENEMkwiLCAiUERDRDYiLCAiUERDRDQiLCAiRkFTIiwgIlRSQUREIiwgIkRBUCIsICJEQUQxIiwgIkRBUDMiLCAiQ0lERUIiLCAiQ0lERUMiLCAiQ0RJUDEiLCAiUElERDEiLCAiREVERDIiKQpjeXRva2luZSA8LSBjKCAiSUw2UiIsICJUTkZSU0YxMUIiLCAiVFJBRjYiLCAiVE5GUlNGMTBBIiwgIklMMVIxIiwgIklMMTdSQiIsICJJTDE3UkEiLCAiSUwxOFIxIiwgIk1BUEsxNSIsICJNQVAzSzEwIiwgIk1BUDJLMiIsICJNQVAzSzMiLCAiTUFQSzciLCAiVE5GQUlQNiIsICJUTkZBSVAzIiwgIlRORkFJUDgiLCAiVE5GQUlQMSIsICJORktCSUEiLCAiVExSMSIsICJUTFI5IiwgIlRMUjQiLCAiVExSNSIsICJUTFIyIiwgIlRMUjMiLCAiSUwxMFJCIiwgIklMMTBSQSIpCm11Y2luIDwtIGMoIk1VQzEiLCAiTVVDNCIsICJNVUMzQSIsICJNVUMxMyIsICJNVUM2IiwgIk1VQzVBQyIsICJNVUM1QiIpCgpnZW5lZ3JvdXBzIDwtIGRvLmNhbGwoYywgbGlzdCh0aWdodGp1bmN0aW9uLCBveHN0cmVzcywgZXJzdHJlc3MsIGNlbGxkZWF0aCwgY3l0b2tpbmUpKQoKYGBgCgoKYGBge3J9CiMgTG9hZCBpbiByZXNfZGZBVE0gCnJlc19kZkFUTXZvbGNhbm9nZW5lcyA8LSByZXNBVE1fZGYKCiMgUmVtb3ZlIHJvd3Mgd2l0aCBsMmZjIG9yIHBhZGogb2YgIk5BIgpyZXNfZGZBVE12b2xjYW5vZ2VuZXMgPC0gcmVzX2RmQVRNdm9sY2Fub2dlbmVzWyFpcy5uYShyZXNfZGZBVE12b2xjYW5vZ2VuZXMkbG9nMkZvbGRDaGFuZ2UpLCBdCnJlc19kZkFUTXZvbGNhbm9nZW5lcyA8LSByZXNfZGZBVE12b2xjYW5vZ2VuZXNbIWlzLm5hKHJlc19kZkFUTXZvbGNhbm9nZW5lcyRwYWRqKSwgXQoKIyBQb3B1bGF0ZSBhIG5ldyBjb2x1bW4gd2l0aCBhICIxIiBpZiBnZW5lIHN5bWJvbCBjb3JyZXNwb25kcyB0byBvbmUgb2YgdGhlIGdlbmVncm91cHMgYW5kIGEgIjAiIGlmIG5vdC4gU29ydCBpbiBkZXNjZW5kaW5nIG9yZGVyLiBXaGVuIGNyZWF0aW5nIHRoZSBwbG90LCB0aGlzIHdpbGwgYWxsb3cgdGhlIGdlbmVncm91cCBwb2ludHMgdG8gYmUgYnJvdWdodCB0byB0aGUgZnJvbnQgYW5kIGVhc2lseSBzZWVuLgpyZXNfZGZBVE12b2xjYW5vZ2VuZXMgJT4lIG11dGF0ZSh2b2xjYW5vaW50ZWdlciA9IGlmZWxzZShzeW1ib2wgJWluJSBnZW5lZ3JvdXBzLCAxLCAwKSkgLT4gcmVzX2RmQVRNdm9sY2Fub2dlbmVzCnJlc19kZkFUTXZvbGNhbm9nZW5lcyA8LSByZXNfZGZBVE12b2xjYW5vZ2VuZXNbb3JkZXIocmVzX2RmQVRNdm9sY2Fub2dlbmVzJHZvbGNhbm9pbnRlZ2VyKSxdCgojIFBvcHVsYXRlIGEgbmV3IGNvbHVtbiB3aXRoIHRoZSBnZW5lIHN5bWJvbCBpZiBsMmZjIGlzIDwtMSBvciA+MSBBTkQgcGFkaiBpcyA8MTBlLTEwIChTUFJSMyBhbHNvIGluY2x1ZGVkIGJlY2F1c2UgaXQncyB2aXN1YWxseSBzaWduaWZpY2FudCkuIFRoaXMgbWFrZXMgbGFiZWxpbmcgZWFzaWVyIGluIHRoZSB2b2xjYW5vIHBsb3QuIApyZXNfZGZBVE12b2xjYW5vZ2VuZXMgJT4lIG11dGF0ZShzaWdnZW5lcyA9IGlmZWxzZSgoKGxvZzJGb2xkQ2hhbmdlID4gMSB8IGxvZzJGb2xkQ2hhbmdlIDwgLTEpICYgcGFkaiA8IDEwZS0xMCkgfCBzeW1ib2wgPT0gIlNQUlIzIiAsIHN5bWJvbCwgIiIpKSAtPiByZXNfZGZBVE12b2xjYW5vZ2VuZXMKCmBgYAoKCmBgYHtyfQogICMgY3JlYXRlIGN1c3RvbSBrZXktdmFsdWUgcGFpcnMgZm9yIGRpZmZlcmVudCBjZWxsLXR5cGVzCiAgIyB0aGlzIGNhbiBiZSBhY2hpZXZlZCB3aXRoIG5lc3RlZCBpZmVsc2Ugc3RhdGVtZW50cwprZXl2YWxzLmNvbG9yQVRNIDwtIAogIGlmZWxzZShyZXNfZGZBVE12b2xjYW5vZ2VuZXMkc3ltYm9sICVpbiUgdGlnaHRqdW5jdGlvbiwgIm1hZ2VudGEiLCAKICAgICAgICAgaWZlbHNlKHJlc19kZkFUTXZvbGNhbm9nZW5lcyRzeW1ib2wgJWluJSBveHN0cmVzcywgImN5YW4yIiwgCiAgICAgICAgICAgICAgICBpZmVsc2UocmVzX2RmQVRNdm9sY2Fub2dlbmVzJHN5bWJvbCAlaW4lIGVyc3RyZXNzLCAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNfZGZBVE12b2xjYW5vZ2VuZXMkc3ltYm9sICVpbiUgY2VsbGRlYXRoLCAiZ29sZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzX2RmQVRNdm9sY2Fub2dlbmVzJHN5bWJvbCAlaW4lIGN5dG9raW5lLCAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyZXk3MCIpKSkpKSMpCgogIGtleXZhbHMuY29sb3JBVE1baXMubmEoa2V5dmFscy5jb2xvckFUTSldIDwtICJncmV5NjkiCiAgbmFtZXMoa2V5dmFscy5jb2xvckFUTSlba2V5dmFscy5jb2xvckFUTSA9PSAiZ3JleTcwIl0gPC0gJ1ogcmVzdCcKICBuYW1lcyhrZXl2YWxzLmNvbG9yQVRNKVtrZXl2YWxzLmNvbG9yQVRNID09ICJtYWdlbnRhIl0gPC0gJ1RpZ2h0IEp1bmN0aW9ucycKICBuYW1lcyhrZXl2YWxzLmNvbG9yQVRNKVtrZXl2YWxzLmNvbG9yQVRNID09ICJjeWFuMiJdIDwtICdPeGlkYXRpdmUgU3RyZXNzJwogIG5hbWVzKGtleXZhbHMuY29sb3JBVE0pW2tleXZhbHMuY29sb3JBVE0gPT0gImJsdWUiXSA8LSAnRVIgU3RyZXNzJwogIG5hbWVzKGtleXZhbHMuY29sb3JBVE0pW2tleXZhbHMuY29sb3JBVE0gPT0gImdvbGQiXSA8LSAnQ2VsbCBEZWF0aCcKICBuYW1lcyhrZXl2YWxzLmNvbG9yQVRNKVtrZXl2YWxzLmNvbG9yQVRNID09ICJyZWQiXSA8LSAnQ3l0b2tpbmVzJwpgYGAKCgpgYGB7cn0Kdm9sY2Fub19BVE1fZ3JvdXBfMDUgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc19kZkFUTXZvbGNhbm9nZW5lcywKICAgICAgICAgICAgICAgIGxhYiA9IHJlc19kZkFUTXZvbGNhbm9nZW5lcyRzaWdnZW5lcywKICAgICAgICAgICAgICAgIGxhYlNpemUgPSAzLjUsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC4wNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAiZ3JleTMwIiwKICAgICAgICAgICAgICAgIHR5cGVDb25uZWN0b3JzID0gImNsb3NlZCIsCiAgICAgICAgICAgICAgICBlbmRzQ29ubmVjdG9ycyA9ICJmaXJzdCIsCiAgICAgICAgICAgICAgICBsZW5ndGhDb25uZWN0b3JzID0gdW5pdCgxMGUtNSwgJ25wYycpLAogICAgICAgICAgICAgICAgeCA9ICdsb2cyRm9sZENoYW5nZScsCiAgICAgICAgICAgICAgICB5ID0gJ3BhZGonLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoLTQsNCksCiAgICAgICAgICAgICAgICB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgY2FwdGlvbiA9ICIiLAogICAgICAgICAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscy5jb2xvckFUTSwKICAgICAgICAgICAgICAgIGhsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIHZsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGNvbEFscGhhID0gMC41LAogICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMywKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgbGFiQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGN1dG9mZkxpbmVDb2wgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgYm9yZGVyID0gImZ1bGwiLAogICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAibm9uZSIKICAgICAgICAgICAgICAgICkKdm9sY2Fub19BVE1fZ3JvdXBfMDUKYGBgCgpgYGB7cn0Kdm9sY2Fub19BVE1fZ3JvdXBfMDEgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc19kZkFUTXZvbGNhbm9nZW5lcywKICAgICAgICAgICAgICAgIGxhYiA9IHJlc19kZkFUTXZvbGNhbm9nZW5lcyRzaWdnZW5lcywKICAgICAgICAgICAgICAgIGxhYlNpemUgPSAzLjUsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC4wNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAiZ3JleTMwIiwKICAgICAgICAgICAgICAgIHR5cGVDb25uZWN0b3JzID0gImNsb3NlZCIsCiAgICAgICAgICAgICAgICBlbmRzQ29ubmVjdG9ycyA9ICJmaXJzdCIsCiAgICAgICAgICAgICAgICBsZW5ndGhDb25uZWN0b3JzID0gdW5pdCgxMGUtNSwgJ25wYycpLAogICAgICAgICAgICAgICAgeCA9ICdsb2cyRm9sZENoYW5nZScsCiAgICAgICAgICAgICAgICB5ID0gJ3BhZGonLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoLTQsNCksCiAgICAgICAgICAgICAgICB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgY2FwdGlvbiA9ICIiLAogICAgICAgICAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscy5jb2xvckFUTSwKICAgICAgICAgICAgICAgIGhsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIHZsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGNvbEFscGhhID0gMC41LAogICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMywKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjAxLAogICAgICAgICAgICAgICAgbGFiQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGN1dG9mZkxpbmVDb2wgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgYm9yZGVyID0gImZ1bGwiLAogICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAibm9uZSIKICAgICAgICAgICAgICAgICkKdm9sY2Fub19BVE1fZ3JvdXBfMDEKYGBgCmBgYHtyfQp2b2xjYW5vX0FUTV9ncm91cF8wMDEgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc19kZkFUTXZvbGNhbm9nZW5lcywKICAgICAgICAgICAgICAgIGxhYiA9IHJlc19kZkFUTXZvbGNhbm9nZW5lcyRzaWdnZW5lcywKICAgICAgICAgICAgICAgIGxhYlNpemUgPSAzLjUsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC4wNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAiZ3JleTMwIiwKICAgICAgICAgICAgICAgIHR5cGVDb25uZWN0b3JzID0gImNsb3NlZCIsCiAgICAgICAgICAgICAgICBlbmRzQ29ubmVjdG9ycyA9ICJmaXJzdCIsCiAgICAgICAgICAgICAgICBsZW5ndGhDb25uZWN0b3JzID0gdW5pdCgxMGUtNSwgJ25wYycpLAogICAgICAgICAgICAgICAgeCA9ICdsb2cyRm9sZENoYW5nZScsCiAgICAgICAgICAgICAgICB5ID0gJ3BhZGonLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoLTQsNCksCiAgICAgICAgICAgICAgICB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgY2FwdGlvbiA9ICIiLAogICAgICAgICAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscy5jb2xvckFUTSwKICAgICAgICAgICAgICAgIGhsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIHZsaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGNvbEFscGhhID0gMC41LAogICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMywKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjAwMSwKICAgICAgICAgICAgICAgIGxhYkNvbCA9ICdibGFjaycsCiAgICAgICAgICAgICAgICBjdXRvZmZMaW5lQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgIGJvcmRlciA9ICJmdWxsIiwKICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gIm5vbmUiCiAgICAgICAgICAgICAgICApCnZvbGNhbm9fQVRNX2dyb3VwXzAwMQpgYGAKYGBge3J9Cmdnc2F2ZSh2b2xjYW5vX0FUTV9ncm91cF8wMSwgZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9hbmFWU2Flci92b2xjYW5vX2F0bV9ncm91cF8wMS5wZGYiLCBkZXZpY2UgPSAicGRmIiwgaGVpZ2h0ID0gNiwgd2lkdGggPSA2KQpnZ3NhdmUodm9sY2Fub19BVE1fZ3JvdXBfMDUsIGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvYW5hVlNhZXIvdm9sY2Fub19hdG1fZ3JvdXBfMDUucGRmIiwgZGV2aWNlID0gInBkZiIsIGhlaWdodCA9IDYsIHdpZHRoID0gNikKZ2dzYXZlKHZvbGNhbm9fQVRNX2dyb3VwXzAwMSwgZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9hbmFWU2Flci92b2xjYW5vX2F0bV9ncm91cF8wMDEucGRmIiwgZGV2aWNlID0gInBkZiIsIGhlaWdodCA9IDYsIHdpZHRoID0gNikKYGBgCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCgoKCg==